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

Pipeline retry clause : expose the retry number

    XMLWordPrintable

    Details

    • Similar Issues:

      Description

      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.

        Attachments

          Activity

          Hide
          abayer 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?

          Show
          abayer 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?
          Hide
          abayer 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.

          Show
          abayer 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.
          Hide
          jimklimov 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.

          Show
          jimklimov 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.
          Hide
          jimklimov 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

          Show
          jimklimov 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
          Hide
          abayer Andrew Bayer added a comment -

          Jim Klimov - 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.

          Show
          abayer Andrew Bayer added a comment - Jim Klimov - 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.
          Hide
          vmj 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.

          Show
          vmj 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.
          Hide
          mcascone 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
          Show
          mcascone 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

            People

            Assignee:
            Unassigned Unassigned
            Reporter:
            jimklimov Jim Klimov
            Votes:
            5 Vote for this issue
            Watchers:
            9 Start watching this issue

              Dates

              Created:
              Updated: