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

Stage locks are created for skipped stages in declarative pipeline

      Given the following declarative pipeline:

      pipeline {
        stages {
          stage('Example stage') {
            when { expression { false } }
            options { lock resource: 'example resource' }
            steps { // ... }
          }
        }
      }
      

      Even though 'example stage' is skipped due to the when conditional, a lockable resource 'example resource' is created (if it doesn't already exist) and a lock is acquired on it. I think this is counter intuitive. The consequence is also really bad – a skipped stage might actually make the whole build hang (possibly for a long time) because it needs to acquire a lock on a busy resource (typically used by another build).

          [JENKINS-51865] Stage locks are created for skipped stages in declarative pipeline

          Thomas Johansen created issue -
          Thomas Johansen made changes -
          Description Original: Given the following declarative pipeline:
          {noformat}
          pipeline {
            stages {
              stage('Example stage') {
                when { expression { false } }
                options { lock resource: 'example resource' }
                steps { // ... }
              }
            }
          }
          {noformat}

          Even though 'example stage' is skipped due to the when conditional, a lockable resource 'example resource' is created (if it doesn't already exist) and a lock is acquired on it. I think this is counter intuitive -- one would not expect the lock to be acquired when the stage is skipped.
          New: Given the following declarative pipeline:
          {noformat}
          pipeline {
            stages {
              stage('Example stage') {
                when { expression { false } }
                options { lock resource: 'example resource' }
                steps { // ... }
              }
            }
          }
          {noformat}
          Even though 'example stage' is skipped due to the when conditional, a lockable resource 'example resource' is created (if it doesn't already exist) and a lock is acquired on it. I think this is counter intuitive. The consequence is also really bad – a skipped stage might actually make the whole build hang (possibly for a long time) because it needs to acquire a lock on a busy resource (typically used by another build).

          abayer: This issue is possibly tagged incorrectly. I suspect that component=pipeline-model-definition-plugin might be correct?

          Thomas Johansen added a comment - abayer : This issue is possibly tagged incorrectly. I suspect that component=pipeline-model-definition-plugin might be correct?

          Andrew Bayer added a comment -

          This is expected - the lock is acquired before we know to skip the stage. It still gets released at the end of the stage, yes?

          Andrew Bayer added a comment - This is expected - the lock is acquired before we know to skip the stage. It still gets released at the end of the stage, yes?
          Andrew Bayer made changes -
          Component/s New: pipeline-model-definition-plugin [ 21706 ]
          Component/s Original: lockable-resources-plugin [ 18222 ]
          Assignee New: Andrew Bayer [ abayer ]

          Ok, got it. So this is a feature request. I was really happy when the 'beforeAgent' option was introduced to the when block. Guess I'm looking for a 'beforeLock' option too, then.

          The lock is released as it should. The problem (or rather my problem) is that the lock is required at all. My current workaround is to rename the lock resource when the stage should be skipped, but it makes the code a little messy.

          Thomas Johansen added a comment - Ok, got it. So this is a feature request. I was really happy when the 'beforeAgent' option was introduced to the when block. Guess I'm looking for a 'beforeLock' option too, then. The lock is released as it should. The problem (or rather my  problem) is that the lock is required at all. My current workaround is to rename the lock resource when the stage should be skipped, but it makes the code a little messy.

          Andrew Bayer added a comment -

          So the only way we could address this directly would be to add a beforeOptions flag to when - but I'm not sure that's actually worth doing. You can always put lock or timeout (and any other block-scoped options) in your steps instead. The more complexity we add to when flags (since we're already adding beforeInput in JENKINS-50880), the hairier the code gets, and this case is one that can largely be worked around (unlike with agent and input). The workaround would create scenarios where, say, timeout or lock wouldn't be in place for acquiring the agent or waiting for input, but it would still work fine for everything in steps. Does that sound reasonable to you?

          Andrew Bayer added a comment - So the only way we could address this directly would be to add a beforeOptions flag to when - but I'm not sure that's actually worth doing. You can always put lock or timeout (and any other block-scoped options ) in your steps instead. The more complexity we add to when flags (since we're already adding beforeInput in JENKINS-50880 ), the hairier the code gets, and this case is one that can largely be worked around (unlike with agent and input ). The workaround would create scenarios where, say, timeout or lock wouldn't be in place for acquiring the agent or waiting for input , but it would still work fine for everything in steps . Does that sound reasonable to you?

          abayer perhaps we could work around this by using an expression in the quantity of the lock, e.g.

          pipeline {
            stages {
              stage('Example stage') {
                when { expression { false } }
                options { lock resource: 'example resource', quantity: expr ? 1 : 0 }
                steps { // ... }
              }
            }
          }
          

          What I do not know is if declarative supports numerical expressions

          Stephen Connolly added a comment - abayer perhaps we could work around this by using an expression in the quantity of the lock, e.g. pipeline { stages { stage( 'Example stage' ) { when { expression { false } } options { lock resource: 'example resource' , quantity: expr ? 1 : 0 } steps { // ... } } } } What I do not know is if declarative supports numerical expressions

          so `quantity:0` doens't work as that is the default value and seems to indicate "grab all".

          I'm now trying:

          pipeline {
            stages {
              stage('Example stage') {
                when { branch 'master' }
                options { lock resource: "${BRANCH_NAME=='master' ? 'example resource':'dummy'}" }
                steps { // ... }
              }
            }
          }
          

          We'll see if that is an acceptable workaround for my use case

          Stephen Connolly added a comment - so `quantity:0` doens't work as that is the default value and seems to indicate "grab all". I'm now trying: pipeline { stages { stage( 'Example stage' ) { when { branch 'master' } options { lock resource: "${BRANCH_NAME== 'master' ? 'example resource' : 'dummy' }" } steps { // ... } } } } We'll see if that is an acceptable workaround for my use case
          Stephen Connolly made changes -
          Attachment New: Screenshot 2019-01-30 at 10.56.27.png [ 45838 ]

            famod Falko Modler
            thxmasj Thomas Johansen
            Votes:
            5 Vote for this issue
            Watchers:
            11 Start watching this issue

              Created:
              Updated:
              Resolved: