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

Add support of throttling of the entire build in Declarative Pipeline

    Details

    • Similar Issues:

      Description

      So, I'm having this problem that I described in a similar bug for the lockable-resource plugin (JENKINS-45138). I said to myself, "oh, hey, I remember being able to throttle executions on a per-agent basis!"

      Imagine my surprise when I hit the documentation and find that throttle is only applicable inside a step.

      I need to acquire, use, and cleanup exclusive access to a resource on each agent. Will throttle work how I expect?

      step('foo') {
          throttle(['foo-label'])
          bat '... acquire the resource...'
          bat '... use the resource...'
      }
      post {
          always {
              bat '... cleanup the resource...'
          }
      }
      

        Attachments

          Activity

          Hide
          sharadholani Sharad Holani added a comment - - edited

          Jay Spang

           

           

           

           

          • I tried the step you suggested. Added throttle settings in manage jenkins. Added  throttle(categories: ['test-category']) in options. Also added the code suggested by Kyle Walker. But the number of builds are not getting throttled.
          Show
          sharadholani Sharad Holani added a comment - - edited Jay Spang         I tried the step you suggested. Added throttle settings in manage jenkins. Added  throttle(categories: ['test-category'] ) in options. Also added the code suggested by Kyle Walker . But the number of builds are not getting throttled.
          Hide
          metamilk Dmitry Mamchur added a comment - - edited

          Hello, I'm having the same problem: 

          options {
            throttle(['shared-workspace'])
          }

           doesn't work for the entire build in a declarative job.

          As a workaround, I'm using shared libraries:
          1) define the entire declarative pipeline in a shared library var, as per https://jenkins.io/blog/2017/10/02/pipeline-templates-with-shared-libraries/
          2) surround pipeline invocation with throttle, e.g.

          Jenkinsfile
          throttle(['shared-workspace']) {
            myDeliveryPipeline {
                branch = 'master'
                scmUrl = 'ssh://git@myScmServer.com/repos/myRepo.git'
                email = 'team@example.com'
                serverPort = '8080'
                developmentServer = 'dev-myproject.mycompany.com'
                stagingServer = 'staging-myproject.mycompany.com'
                productionServer = 'production-myproject.mycompany.com'
            }
          }
          

          Hope this will be helpful to someone!

          Show
          metamilk Dmitry Mamchur added a comment - - edited Hello, I'm having the same problem:  options {   throttle([ 'shared-workspace' ]) }  doesn't work for the entire build in a declarative job. As a workaround, I'm using shared libraries: 1) define the entire declarative pipeline in a shared library var, as per https://jenkins.io/blog/2017/10/02/pipeline-templates-with-shared-libraries/ 2) surround pipeline invocation with throttle, e.g. Jenkinsfile throttle([ 'shared-workspace' ]) { myDeliveryPipeline { branch = 'master' scmUrl = 'ssh: //git@myScmServer.com/repos/myRepo.git' email = 'team@example.com' serverPort = '8080' developmentServer = 'dev-myproject.mycompany.com' stagingServer = 'staging-myproject.mycompany.com' productionServer = 'production-myproject.mycompany.com' } } Hope this will be helpful to someone!
          Hide
          medianick Nick Jones added a comment -

          I had to revert back to a scripted pipeline in order to get throttling to work as intended. The issue seems to be that the throttle option in a Declarative pipeline occurs on a particular agent node, and it's either too late – the executor is already consumed – or it's simply a no-op, but in any case, I'm not seeing any actual evidence of throttling, either overall or per node.

          pipeline {
            agent { label 'foo' }
            options {
              throttle(categories: ['MyCategory']) // <-- doesn't do anything, even with MyCategory defined in the system configuration
            }
            stages {
              // ...
            }
          }
          

          What I would have wanted is either to have the throttle option take effect before the agent is selected, or some sort of declarative syntax that would let me have agent none at the top level of the pipeline (where the throttle option is specified), then the ability to specify a particular agent for all the actual stages to be executed (Build, Test, Publish, etc.). I tried this:

          pipeline {
            agent none // <-- to avoid having an agent allocated before the throttle category is evaluated
            options {
              throttle(categories: ['MyCategory'])
            }
            stages {
              stage('Overall') {
                agent {
                  label 'foo' // <-- to get the real agent I want for the real stages
                }
                stages {
                  stage('Build') {
                     // ...
                  }
                  stage('Test') {
                    // ...
                  }
                }
              }
            }
          }
          

          But it simply hung with no useful output. If there's some other way to have agent none at the top level, then a single, reused agent for the actual stages within, I'd be interested to hear about it. I know I could have an agent per stage (Build, Test, etc.), but that wouldn't work for me – it has to be the same machine for all of these, and I'd rather not stash and unstash all the artifacts I need between these stages.

          Show
          medianick Nick Jones added a comment - I had to revert back to a scripted pipeline in order to get throttling to work as intended. The issue seems to be that the throttle option in a Declarative pipeline occurs on a particular agent node, and it's either too late – the executor is already consumed – or it's simply a no-op, but in any case, I'm not seeing any actual evidence of throttling, either overall or per node. pipeline { agent { label 'foo' } options { throttle(categories: [ 'MyCategory' ]) // <-- doesn't do anything, even with MyCategory defined in the system configuration } stages { // ... } } What I would have wanted is either to have the throttle option take effect before the agent is selected, or some sort of declarative syntax that would let me have agent none at the top level of the pipeline (where the throttle option is specified), then the ability to specify a particular agent for all the actual stages to be executed (Build, Test, Publish, etc.). I tried this: pipeline { agent none // <-- to avoid having an agent allocated before the throttle category is evaluated options { throttle(categories: [ 'MyCategory' ]) } stages { stage( 'Overall' ) { agent { label 'foo' // <-- to get the real agent I want for the real stages } stages { stage( 'Build' ) { // ... } stage( 'Test' ) { // ... } } } } } But it simply hung with no useful output. If there's some other way to have agent none at the top level, then a single, reused agent for the actual stages within, I'd be interested to hear about it. I know I could have an agent per stage (Build, Test, etc.), but that wouldn't work for me – it has to be the same machine for all of these, and I'd rather not stash and unstash all the artifacts I need between these stages.
          Hide
          guybanay Guy Banay added a comment -

          Hi,

          Any update with this issue?

          The property "maxConcurrentPerNode" is not working

           

          Thanks

           

          Show
          guybanay Guy Banay added a comment - Hi, Any update with this issue? The property "maxConcurrentPerNode" is not working   Thanks  
          Hide
          medianick Nick Jones added a comment -

          I'm seeing what Guy Banay sees. I'm now testing a Declarative Pipeline workaround as Kyle Walker suggested – namely, putting the properties block outside the pipeline altogether – and it works, but it only honors the maxConcurrentTotal property, not the maxConcurrentNode one. Very simple repro (assuming a "ThrottleTest" category is configured globally):

          properties([
            [
              $class: 'ThrottleJobProperty',
              categories: ['ThrottleTest'],
              throttleEnabled: true,
              throttleOption: 'category'
            ],
          ])
          
          pipeline {
              agent any
              stages {
                  stage('Long-running') {
                      steps {
                          input message: 'Shall we continue?'
                          echo "Thanks! Continuing."
                      }
                  }
              }
          }
          

          If I configure a maximum of 5 concurrent builds across all nodes, but only 1 per node, the only limit enforced is the total limit; a single build agent can still run as many builds of this job as it has executors. Only the maxConcurrentTotal takes effect.

          Show
          medianick Nick Jones added a comment - I'm seeing what Guy Banay sees. I'm now testing a Declarative Pipeline workaround as Kyle Walker suggested – namely, putting the properties block outside the pipeline altogether – and it works , but it only honors the maxConcurrentTotal property, not the maxConcurrentNode one. Very simple repro (assuming a "ThrottleTest" category is configured globally): properties([ [ $class: 'ThrottleJobProperty' , categories: [ 'ThrottleTest' ], throttleEnabled: true , throttleOption: 'category' ], ]) pipeline { agent any stages { stage( ' Long -running' ) { steps { input message: 'Shall we continue ?' echo "Thanks! Continuing." } } } } If I configure a maximum of 5 concurrent builds across all nodes, but only 1 per node, the only limit enforced is the total limit; a single build agent can still run as many builds of this job as it has executors. Only the maxConcurrentTotal takes effect.

            People

            • Assignee:
              abayer Andrew Bayer
              Reporter:
              anthonymastrean Anthony Mastrean
            • Votes:
              18 Vote for this issue
              Watchers:
              25 Start watching this issue

              Dates

              • Created:
                Updated: