Uploaded image for project: 'Jenkins'
  1. Jenkins
  2. JENKINS-52774

Restart from Stage doesn't restore global variable

    • Icon: Bug Bug
    • Resolution: Not A Defect
    • Icon: Major Major
    • None
    • Jenkins ver. 2.121.2 with up-to-date plugins

      The attached Jenkinsfile can be used to reproduce this issue.

      Running the Pipeline the first time, everything works as expected:

      run a)
      ------

      [Pipeline] {
      [Pipeline] timestamps
      [Pipeline] {

      [Pipeline] stage
      [Pipeline] { (one)

      [Pipeline] script
      [Pipeline]

      { [Pipeline] echo 00:00:06.159 simpletest-17 [Pipeline] }

      [Pipeline] // script

      [Pipeline] }
      [Pipeline] // stage

      [Pipeline] stage
      [Pipeline] { (two)
      [Pipeline] script
      [Pipeline]

      { [Pipeline] echo 00:00:09.465 simpletest-17 [Pipeline] echo 00:00:10.274 simpletest-17 [Pipeline] }

      [Pipeline] // script

      [Pipeline] }
      [Pipeline] // stage
      [Pipeline] }
      [Pipeline] // timestamps

      [Pipeline] }
      [Pipeline] // node

      [Pipeline] End of Pipeline
      Finished: SUCCESS

       

      If it is restarted from stage 'two', the value of the global Map member is null. I would expect to have the value from the last run there:

       

      run b) - restart from stage two
      -------------------------------
      [Pipeline] timestamps
      [Pipeline] {
      [Pipeline] stage
      [Pipeline]

      { (one) Stage "one" skipped due to this build restarting at stage "two" [Pipeline] }

      [Pipeline] // stage
      [Pipeline] stage
      [Pipeline] { (two)
      [Pipeline] script
      [Pipeline]

      { [Pipeline] echo 00:00:07.975 simpletest-18 [Pipeline] echo 00:00:08.408 null --8<-- i would expect to get 'simpletest-17' instead of 'null' --8<-- [Pipeline] }

      [Pipeline] // script
      [Pipeline] }
      [Pipeline] // stage
      [Pipeline] }
      [Pipeline] // timestamps
      [Pipeline] }
      [Pipeline] // node
      [Pipeline] End of Pipeline
      Finished: SUCCESS

       

          [JENKINS-52774] Restart from Stage doesn't restore global variable

          Andrew Bayer added a comment -

          Lemme think on this. It may be viable for us to be able to do something like record some information in the previous build explicitly and then be able to refer to that data in the restarted build. Like (and this is really, really hand-wave-y, so don't take this as anything but speculation) this, maybe?

          stage('some-stage') {
            steps {
              setPersistentEnv(key: "FOO", value: "abcd")
            }
          }
          stage('stage-to-restart') {
            steps {
              echo "FOO is ${env.FOO}"
            }
          }
          

          Again, totally not sure if that's actually useful or if it's even possible to implement cleanly.

          Andrew Bayer added a comment - Lemme think on this. It may be viable for us to be able to do something like record some information in the previous build explicitly and then be able to refer to that data in the restarted build. Like (and this is really, really hand-wave-y, so don't take this as anything but speculation) this, maybe? stage( 'some-stage' ) { steps { setPersistentEnv(key: "FOO" , value: "abcd" ) } } stage( 'stage-to-restart' ) { steps { echo "FOO is ${env.FOO}" } } Again, totally not sure if that's actually useful or if it's even possible to implement cleanly.

          Wow!  That would indeed solve my problem at least: I just need to save a number.  For a few values this would be more than enough.  And for something more elaborate the stash/unstash would be justifiable.

          This could perhaps provide another workaround for https://issues.jenkins-ci.org/browse/JENKINS-53193  as checking for the value of a variable can indicate if it is a restart or not.

           

          Fernando Nasser added a comment - Wow!  That would indeed solve my problem at least: I just need to save a number.  For a few values this would be more than enough.  And for something more elaborate the stash/unstash would be justifiable. This could perhaps provide another workaround for https://issues.jenkins-ci.org/browse/JENKINS-53193   as checking for the value of a variable can indicate if it is a restart or not.  

          Andrew Bayer added a comment -

          I feel like it's probably not ideal for that latter scenario, but I'll talk about that over on JENKINS-53913. =)

          Andrew Bayer added a comment - I feel like it's probably not ideal for that latter scenario, but I'll talk about that over on JENKINS-53913 . =)

          Daniel Kurzynski added a comment - - edited

          What about the original issue? Is there a plan to restore more in the future than just the stashes. 
          Our use case is, that we are reading some configuration in the init stage and store them in a global variable or singleton object (object defined in vars of a lib). The configuration is basically about which stages in the declarative pipeline should be skipped but it contains also information to define the behavior of stages, e.g. where to deploy. 
          Without that configuration it does not make sense to restart at a certain stage, because it will not skip stages as defined in the configuration or deployment information are missing. 
          Thus, we need the possibility to restore additional state or have some initialization method in case the pipeline is restarted at a later stage.

          Daniel Kurzynski added a comment - - edited What about the original issue? Is there a plan to restore more in the future than just the stashes.  Our use case is, that we are reading some configuration in the init stage and store them in a global variable or singleton object (object defined in vars of a lib). The configuration is basically about which stages in the declarative pipeline should be skipped but it contains also information to define the behavior of stages, e.g. where to deploy.  Without that configuration it does not make sense to restart at a certain stage, because it will not skip stages as defined in the configuration or deployment information are missing.  Thus, we need the possibility to restore additional state or have some initialization method in case the pipeline is restarted at a later stage.

          Andrew Bayer added a comment -

          kurzy - no, just stashes - preserving program state (like global variables or singletons) is a deeper, more complex problem area than Declarative goes, and is replete with painpoints. Sorry.

          Andrew Bayer added a comment - kurzy - no, just stashes - preserving program state (like global variables or singletons) is a deeper, more complex problem area than Declarative goes, and is replete with painpoints. Sorry.

          kurzy I saved some state in a file and if it fails and is restarted I read what I need from that file (you need set preserveStashes() I believe, I did it but I am not sure). It worked fine. For skipping steps, etc., there is a JIRA to get the isRestartedRun() and isRestartedStage() into variables that can be used outside of the when{}

          Fernando Nasser added a comment - kurzy I saved some state in a file and if it fails and is restarted I read what I need from that file (you need set preserveStashes() I believe, I did it but I am not sure). It worked fine. For skipping steps, etc., there is a JIRA to get the isRestartedRun() and isRestartedStage() into variables that can be used outside of the when{}

          Alistair Leszkiewicz added a comment - - edited

          abayer This issue is affecting us also, if you can suggest a temporary work around that would help us Thanks

           

          Restarting a stage from the original build will work, but restarting a stage twice does not work (restarting a failed restarted stage).

           

          We rely on environment variables instead of global variables

          Alistair Leszkiewicz added a comment - - edited abayer This issue is affecting us also, if you can suggest a temporary work around that would help us Thanks   Restarting a stage from the original build will work, but restarting a stage twice does not work (restarting a failed restarted stage).   We rely on environment variables instead of global variables

          Frank Gen added a comment -

          Hello,

          We're using a lot of classes in our pipeline libraries, and instead of passing the WorkflowScript in every single function, we are keeping a reference of that WorkflowScript in a Singleton in order to access Pipeline Functions from any of the classes. We are initializing that singleton at the beginning of our pipelines.

          I just noticed that we are losing the reference on the WorkflowScript on restarts, so our Pipeline is failing on the next access to the WorkflowScript singleton...

          Would it be somehow possible for us to reset that reference? Maybe adding some kind of configurable `onResume` callback where we could reset some of those global/singletons ourselves?

          Thanks

          Frank Gen added a comment - Hello, We're using a lot of classes in our pipeline libraries, and instead of passing the WorkflowScript in every single function, we are keeping a reference of that WorkflowScript in a Singleton in order to access Pipeline Functions from any of the classes. We are initializing that singleton at the beginning of our pipelines. I just noticed that we are losing the reference on the WorkflowScript on restarts, so our Pipeline is failing on the next access to the WorkflowScript singleton... Would it be somehow possible for us to reset that reference? Maybe adding some kind of configurable `onResume` callback where we could reset some of those global/singletons ourselves? Thanks

          Jesse Glick added a comment -

          As designed. Restart of stages in Declarative Pipeline simply means running a new build with a flag set to skip earlier stages, and with some stuff copied over like parameters and stashes.

          The CloudBees CI checkpoint step for Scripted syntax does support something close to what is requested here, though not for static variables (fields) in particular; nor are these restored after resuming a build across controller restarts. Use a lexical variable (def) instead, or object instance fields, etc.

          Jesse Glick added a comment - As designed. Restart of stages in Declarative Pipeline simply means running a new build with a flag set to skip earlier stages, and with some stuff copied over like parameters and stashes. The CloudBees CI checkpoint step for Scripted syntax does support something close to what is requested here, though not for static variables (fields) in particular; nor are these restored after resuming a build across controller restarts. Use a lexical variable ( def ) instead, or object instance fields, etc.

          Jesse Glick added a comment -

          (It would be helpful for the Pipeline engine to issue a warning when you are trying to set a static field that this state might be lost. The logging API introduced for JENKINS-31314 could help here. Maybe the engine could track such saves and add them to the program state, though this seems like it would just be encouraging a bad practice. Anyway, again, this would have no effect on the reported issue about Declarative stage restart, which does not operate at the Groovy level and is only effective for truly declarative Jenkinsfile’s with no script blocks or the like.

          Jesse Glick added a comment - (It would be helpful for the Pipeline engine to issue a warning when you are trying to set a static field that this state might be lost. The logging API introduced for JENKINS-31314 could help here. Maybe the engine could track such saves and add them to the program state, though this seems like it would just be encouraging a bad practice. Anyway, again, this would have no effect on the reported issue about Declarative stage restart, which does not operate at the Groovy level and is only effective for truly declarative Jenkinsfile ’s with no script blocks or the like.

            Unassigned Unassigned
            manut Manuel Traut
            Votes:
            21 Vote for this issue
            Watchers:
            25 Start watching this issue

              Created:
              Updated:
              Resolved: