When inside the `retry{}` clause, it may be useful to know which attempt number this is (e.g. to `archiveArtifacts` the debug logs under a uniquely named archive). Expose the retry number as a groovy and/or environment variable.

          [JENKINS-49341] Pipeline retry clause : expose the retry number

          Andrew Bayer added a comment -

          So I can put this in the environment - of course, then it's "2", not 2 - i.e., a String, not an int. I'm trying to think if there's a way I can get around that and have it actually be an int but I don't think I'll be able to.

          What should the count be starting at? First attempt is 0, second attempt (a.k.a. the first retry) is 1, etc? Or first attempt is 1, second attempt is 2, etc?

          Andrew Bayer added a comment - So I can put this in the environment - of course, then it's "2" , not 2 - i.e., a String , not an int . I'm trying to think if there's a way I can get around that and have it actually be an int but I don't think I'll be able to. What should the count be starting at? First attempt is 0, second attempt (a.k.a. the first retry) is 1, etc? Or first attempt is 1, second attempt is 2, etc?

          Andrew Bayer added a comment -

          Also, we could instead do something like env.RETRIES_REMAINING - that's actually simpler, since RetryStepExecution.Callback actually determines when to stop retrying based on counting down to 0 from the specified retry count, so I don't need to do any changes other than just dumping that into the environment.

          Andrew Bayer added a comment - Also, we could instead do something like env.RETRIES_REMAINING - that's actually simpler, since RetryStepExecution.Callback actually determines when to stop retrying based on counting down to 0 from the specified retry count, so I don't need to do any changes other than just dumping that into the environment.

          Jim Klimov added a comment -

          I think the environment representation would be used in `sh` clauses and so shell script would take it into numeric consideration if needed. For groovy it can remain a number if that's easier.

          For starting value in my workaround, 1 was a starting value. Or actually, in the code it went like

          `script { def retrynum = 0; retry { try { retrynum++; ... } / catch...} }`

          So as the build step processing actually started, the value became 1.

          Jim Klimov added a comment - I think the environment representation would be used in `sh` clauses and so shell script would take it into numeric consideration if needed. For groovy it can remain a number if that's easier. For starting value in my workaround, 1 was a starting value. Or actually, in the code it went like `script { def retrynum = 0; retry { try { retrynum++; ... } / catch...} }` So as the build step processing actually started, the value became 1.

          Jim Klimov added a comment -

          Yes, at least for unique naming - dumping a raw unique value is also good
          Even better if the same variable could be "defined" even if empty (or 0) when not inside a retry clause, so accessing it in any context is not an error

          Jim Klimov added a comment - Yes, at least for unique naming - dumping a raw unique value is also good Even better if the same variable could be "defined" even if empty (or 0) when not inside a retry clause, so accessing it in any context is not an error

          Andrew Bayer added a comment -

          jimklimov - that's harder, annoyingly. I don't think I can do that outside of retry. But if you do something like if (env.RETRY_COUNT == null), that'll work fine. It's only if you try to do if (RETRY_COUNT ...) that you'll hit Groovy errors.

          Andrew Bayer added a comment - jimklimov - that's harder, annoyingly. I don't think I can do that outside of retry . But if you do something like if (env.RETRY_COUNT == null) , that'll work fine. It's only if you try to do if (RETRY_COUNT ...) that you'll hit Groovy errors.

          Mikko Värri added a comment - - edited

          Will this be usable outside of pipelines, or is it out of scope?

          One of my projects is not using pipelines, but xml job configs.  Basically, we've got a bunch of jobs with:

             <builders>
               <hudson.tasks.Shell>
                 <command>/bin/sh /some/script.sh ...</command>
               </hudson.tasks.Shell>
             </builders>

          It would be nice to utilize an env var in that command to determine if the command is going to fail for the last time.

           

          Nevermind.  I should have been looking into naginator plugin, which is what we actually use to trigger retries.

          Mikko Värri added a comment - - edited Will this be usable outside of pipelines, or is it out of scope? One of my projects is not using pipelines, but xml job configs.  Basically, we've got a bunch of jobs with:    <builders>      <hudson.tasks.Shell>        <command>/bin/sh /some/script.sh ...</command>      </hudson.tasks.Shell>    </builders> It would be nice to utilize an env var in that command to determine if the command is going to fail for the last time.   Nevermind.  I should have been looking into naginator plugin, which is what we actually use to trigger retries.

          Max Cascone added a comment - - edited

          This is the workaround I thought I'd come up with for this:

          environment {
                  retryCount = '0'
              }
              
              stages {
                  stage ('try') {
                      options {
                          retry(3)
                      }
                      steps {
                          script {
                              tryCount = env.retryCount as Integer
                              echo "first step: tryCount = ${tryCount}"
                              if(tryCount > 0) {
                                  echo 'entered catcher'
                              }
                              
                              tryCount++
                              echo "after bump: tryCount = ${tryCount}"
                              env.retryCount = tryCount as String
                              echo "After set: env.retryCount = ${env.retryCount}"
                              error "${env.retryCount}"
                          }            
                      }
                  }

          But i can't get the env.retryCount to stick, even immediately after setting it:

          [Pipeline] echo
          first step: tryCount = 0
          [Pipeline] echo
          after bump: tryCount = 1
          [Pipeline] echo
          After set: env.retryCount = 0
          [Pipeline] error
          [Pipeline] }
          [Pipeline] // script
          [Pipeline] }
          ERROR: 0
          Retrying
          [Pipeline] {
          [Pipeline] script
          [Pipeline] {
          [Pipeline] echo
          first step: tryCount = 0
          [Pipeline] echo
          after bump: tryCount = 1
          [Pipeline] echo
          After set: env.retryCount = 0
          [Pipeline] error
          [Pipeline] }
          [Pipeline] // script
          [Pipeline] }
          ERROR: 0
          Retrying
          [Pipeline] {
          [Pipeline] script
          [Pipeline] {
          [Pipeline] echo
          first step: tryCount = 0
          [Pipeline] echo
          after bump: tryCount = 1
          [Pipeline] echo
          After set: env.retryCount = 0

          Why isn't that env.tryCount getting set, even locally?
          Also, it seems that the entire environment is reset in a retry, including any changes made to environment variables?

          How can we get the retry count/remaining/whatever to use in our stages?
          thanks.

           

          UPDATE: I knew about this too, but it's still tricky. As explained extremely well by Szymon Stepniak in this post, you can't alter env vars set implicitly in an environment clause. 

          By moving the variable setting into a script block in a stage, it all works as intended.

          pipeline {
              agent any    
              stages {
                  stage ('init') {
                      steps {
                          script {
                              env.retryCount = '0'
                          }
                      }
                  }
                  stage ('try') {
                      options {
                          retry(3)
                      }
                      steps {
                          script {
                              tryCount = env.retryCount as Integer
                              echo "first step: tryCount = ${tryCount}"
                              if(tryCount > 0) {
                                  echo 'entered catcher'
                              }
                              
                              tryCount++
                              echo "after bump: tryCount = ${tryCount}"
                              env.retryCount = "${tryCount}"
                              echo "After set: env.retryCount = ${env.retryCount}"
                              error "${env.retryCount}"
                          }            
                      }
                  }
              }
          } 
          first step: tryCount = 0
          [Pipeline] echo
          after bump: tryCount = 1
          [Pipeline] echo
          After set: env.retryCount = 1
          [Pipeline] error
          [Pipeline] }
          [Pipeline] // script
          [Pipeline] }
          ERROR: 1
          Retrying
          [Pipeline] {
          [Pipeline] script
          [Pipeline] {
          [Pipeline] echo
          first step: tryCount = 1
          [Pipeline] echo
          entered catcher
          [Pipeline] echo
          after bump: tryCount = 2
          [Pipeline] echo
          After set: env.retryCount = 2
          [Pipeline] error
          [Pipeline] }
          [Pipeline] // script
          [Pipeline] }
          ERROR: 2
          Retrying
          [Pipeline] {
          [Pipeline] script
          [Pipeline] {
          [Pipeline] echo
          first step: tryCount = 2
          [Pipeline] echo
          entered catcher
          [Pipeline] echo
          after bump: tryCount = 3
          [Pipeline] echo
          After set: env.retryCount = 3
          [Pipeline] error
          [Pipeline] }
          [Pipeline] // script
          [Pipeline] }
          [Pipeline] // retry
          [Pipeline] }
          [Pipeline] // stage
          [Pipeline] }
          [Pipeline] // node
          [Pipeline] End of Pipeline
          [Checks API] No suitable checks publisher found.
          ERROR: 3
          Finished: FAILURE

          Max Cascone added a comment - - edited This is the workaround I thought I'd come up with for this: environment { retryCount = '0' } stages { stage ( ' try ' ) { options { retry(3) } steps { script { tryCount = env.retryCount as Integer echo "first step: tryCount = ${tryCount}" if (tryCount > 0) { echo 'entered catcher' } tryCount++ echo "after bump: tryCount = ${tryCount}" env.retryCount = tryCount as String echo "After set: env.retryCount = ${env.retryCount}" error "${env.retryCount}" } } } But i can't get the env.retryCount to stick, even immediately after setting it: [Pipeline] echo first step: tryCount = 0 [Pipeline] echo after bump: tryCount = 1 [Pipeline] echo After set: env.retryCount = 0 [Pipeline] error [Pipeline] } [Pipeline] // script [Pipeline] } ERROR: 0 Retrying [Pipeline] { [Pipeline] script [Pipeline] { [Pipeline] echo first step: tryCount = 0 [Pipeline] echo after bump: tryCount = 1 [Pipeline] echo After set: env.retryCount = 0 [Pipeline] error [Pipeline] } [Pipeline] // script [Pipeline] } ERROR: 0 Retrying [Pipeline] { [Pipeline] script [Pipeline] { [Pipeline] echo first step: tryCount = 0 [Pipeline] echo after bump: tryCount = 1 [Pipeline] echo After set: env.retryCount = 0 Why isn't that env.tryCount getting set, even locally? Also, it seems that the entire environment is reset in a retry, including any changes made to environment variables? How can we get the retry count/remaining/whatever to use in our stages? thanks.   UPDATE: I knew about this too, but it's still tricky. As explained extremely well by Szymon Stepniak in this post , you can't alter env vars set implicitly in an environment clause.  By moving the variable setting into a script block in a stage, it all works as intended. pipeline { agent any stages { stage ( 'init' ) { steps { script { env.retryCount = '0' } } } stage ( ' try ' ) { options { retry(3) } steps { script { tryCount = env.retryCount as Integer echo "first step: tryCount = ${tryCount}" if (tryCount > 0) { echo 'entered catcher' } tryCount++ echo "after bump: tryCount = ${tryCount}" env.retryCount = "${tryCount}" echo "After set: env.retryCount = ${env.retryCount}" error "${env.retryCount}" } } } } } first step: tryCount = 0 [Pipeline] echo after bump: tryCount = 1 [Pipeline] echo After set: env.retryCount = 1 [Pipeline] error [Pipeline] } [Pipeline] // script [Pipeline] } ERROR: 1 Retrying [Pipeline] { [Pipeline] script [Pipeline] { [Pipeline] echo first step: tryCount = 1 [Pipeline] echo entered catcher [Pipeline] echo after bump: tryCount = 2 [Pipeline] echo After set: env.retryCount = 2 [Pipeline] error [Pipeline] } [Pipeline] // script [Pipeline] } ERROR: 2 Retrying [Pipeline] { [Pipeline] script [Pipeline] { [Pipeline] echo first step: tryCount = 2 [Pipeline] echo entered catcher [Pipeline] echo after bump: tryCount = 3 [Pipeline] echo After set: env.retryCount = 3 [Pipeline] error [Pipeline] } [Pipeline] // script [Pipeline] } [Pipeline] // retry [Pipeline] } [Pipeline] // stage [Pipeline] } [Pipeline] // node [Pipeline] End of Pipeline [Checks API] No suitable checks publisher found. ERROR: 3 Finished: FAILURE

          Cody Rank added a comment -

          This has be "in progress" for 4 years. Is there any progress on this? The workarounds below are pretty hacky, and don't play well with parallel steps. I'm trying to keep track of retried steps in parallel stages.

          Cody Rank added a comment - This has be "in progress" for 4 years. Is there any progress on this? The workarounds below are pretty hacky, and don't play well with parallel steps. I'm trying to keep track of retried steps in parallel stages.

            Unassigned Unassigned
            jimklimov Jim Klimov
            Votes:
            9 Vote for this issue
            Watchers:
            11 Start watching this issue

              Created:
              Updated: