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

Stopping a parent job doesn't stop the triggered child jobs

      Assume you have a job A that launch a child Job B and that job A has to wait Job B finished to continue its steps.

      If you stopped job A while job B is processing, the job B isn't stopped.
      It should be stopped.

      Precondition:
      I have a parent job "Parent" that triggers child jobs "Child(1-N)", and then blocks waiting for them to finish.

      Action:
      1. Start Parent job.
      2. Wait for children to launch.
      3. Abort Parent job.

      Current result: 
      Parent job aborts but children continue to run. If the child jobs have no meaning outside of the parent, then child jobs have to be manually aborted.

      I can see why you would want this behavior. It is certainly the correct behavior in the "post-build step" case. It is probably correct in the "non-blocking build step" case. In the case of the parent build blocking on children completing, there are definitely scenarios where it is not.

      Desired Enhancement:
      When "Block on child job completion" checkbox is checked, a list of options is shown. Add option to the list: "Child job action when parent job is aborted". Values: "None, continue running (default)", "Abort immediately".

          [JENKINS-11257] Stopping a parent job doesn't stop the triggered child jobs

          Phillip Viana added a comment -

          +1 Nickolay, Sebastian totally vote for this one.

          I can't think of a use case where it makes sense to continue running a downstream job after the upstream job is cancelled.

          Several – if not most – jobs that I see in Jenkins trigger one or more downstream jobs since they are part of a whole. Not cancelling the downstream job is a severe defect, or counter-intuitive and confusing at best.

          In my opinion, if there is such use case pointed out by Sebastian above, there should be an option that allows downstream jobs to keep running after the upstream is cancelled, and this option should be disabled by default.

          Phillip Viana added a comment - +1 Nickolay, Sebastian totally vote for this one. I can't think of a use case where it makes sense to continue running a downstream job after the upstream job is cancelled. Several – if not most – jobs that I see in Jenkins trigger one or more downstream jobs since they are part of a whole. Not cancelling the downstream job is a severe defect, or counter-intuitive and confusing at best. In my opinion, if there is such use case pointed out by Sebastian above, there should be an option that allows downstream jobs to keep running after the upstream is cancelled, and this option should be disabled by default.

          Patrick Pötz added a comment -

          Totally vote for this.
          We would need it for a wrapper job which starts about 100 jobs in parallel.
          And if the config is f****d up all subjobs must be aborted manually.

          Patrick Pötz added a comment - Totally vote for this. We would need it for a wrapper job which starts about 100 jobs in parallel. And if the config is f****d up all subjobs must be aborted manually.

          Anish Dangi added a comment -

          We needed this feature as we trigger and abort jobs from the command line, which makes it easy to abort. The zombie child jobs would tie up our build machines. I added this functionality to the plugin: Here is the relevant commit https://github.com/ad22/parameterized-trigger-plugin/commit/d00a079a580d0b71168c1dd12d5ad8e13c658f94

          Anish Dangi added a comment - We needed this feature as we trigger and abort jobs from the command line, which makes it easy to abort. The zombie child jobs would tie up our build machines. I added this functionality to the plugin: Here is the relevant commit https://github.com/ad22/parameterized-trigger-plugin/commit/d00a079a580d0b71168c1dd12d5ad8e13c658f94

          Here is how this works for our need. I explored quite a few options but this probably the best and easy solution that worked for me.

          1. Install the "post build task" Plugin in jenkins.
                  https://wiki.jenkins.io/display/JENKINS/Post+build+task.
          2.  Add a post build task in the upstream job and add a Log text as "Build was aborted" (When user cancel the job manually the console log will have this text).
          3.  In the Script section of the task, add a ruby code and read step 4.
          4.  I wrote a ruby script(you can convert and use whatever language binding you want) that actually iterates all the downstream jobs and get the full URL corresponding upstream build.
          5. In the ruby script, i pass the Upstream Job's build number and the credentials of the CI User and Api token has an access to make a POST call to stop the job.
          6. The ruby script will return the full URL(s) of the downstream job(s) and make a POST call to REST Api to stop the job.
          7. I had 3 Downstream jobs, alter the script based on the number of downstream jobs.

          P.S: If you ever see 403 returning when stopping the job, probably the credentials you use may not have an adequate permission for the POST call.

          Ruby Script
          =========

           

          /usr/bin/env ruby <<-EORUBY
          
          require 'httparty'
          require 'json'
          
          downstream_jobs = ['downstream_job_1', 'downstream_job_2', 'downstream_job_3']
          downstream_job_url = []
          upstream_build_id = ENV['BUILD_NUMBER']
          auth = {username: ENV['CI_USERNAME'], password: ENV['CI_API_KEY']}
          
          downstream_jobs.each do |dsj|
            response = HTTParty.get("https://<jenkins-server>/job/#{dsj}/api/json?depth=1", basic_auth: auth)
            data = JSON.parse(response.body)['builds']
          
            data.each do |child|
              child ['actions'].each do |c|
                if !c['causes'].nil?
                 c['causes'].each do |d|
                  if d['_class'].include?('hudson.model.Cause$UpstreamCause') && d["upstreamBuild"].to_s ==    upstream_build_id.to_s
                    downstream_job_url.push(child["url"])
                    break
                   end
                 end
               end
             end
           end
          end
          
          
          #Stop all the downstream jobs
          #http://<Jenkins_URL>/job/<Job_Name>/<Build_Number>/stop
          downstream_job_url.each do |ds_url|
            puts "#{ds_url}stop"
            response = HTTParty.post("#{ds_url}stop", basic_auth: auth)
            puts response.code unless response.nil?
          end
          
          EORUBY

          Sridharan Gopalan added a comment - Here is how this works for our need. I explored quite a few options but this probably the best and easy solution that worked for me. Install the "post build task" Plugin in jenkins.       https://wiki.jenkins.io/display/JENKINS/Post+build+task.  Add a post build task in the upstream job and add a Log text as "Build was aborted" (When user cancel the job manually the console log will have this text).  In the Script section of the task, add a ruby code and read step 4.  I wrote a ruby script(you can convert and use whatever language binding you want) that actually iterates all the downstream jobs and get the full URL corresponding upstream build. In the ruby script, i pass the Upstream Job's build number and the credentials of the CI User and Api token has an access to make a POST call to stop the job. The ruby script will return the full URL(s) of the downstream job(s) and make a POST call to REST Api to stop the job. I had 3 Downstream jobs, alter the script based on the number of downstream jobs. P.S: If you ever see 403 returning when stopping the job, probably the credentials you use may not have an adequate permission for the POST call. Ruby Script =========   /usr/bin/env ruby <<-EORUBY require 'httparty' require 'json' downstream_jobs = [ 'downstream_job_1' , 'downstream_job_2' , 'downstream_job_3' ] downstream_job_url = [] upstream_build_id = ENV[ 'BUILD_NUMBER' ] auth = {username: ENV[ 'CI_USERNAME' ], password: ENV[ 'CI_API_KEY' ]} downstream_jobs.each do |dsj| response = HTTParty.get( "https: //<jenkins-server>/job/#{dsj}/api/json?depth=1" , basic_auth: auth) data = JSON.parse(response.body)[ 'builds' ] data.each do |child| child [ 'actions' ].each do |c| if !c[ 'causes' ].nil? c[ 'causes' ].each do |d| if d[ '_class' ].include?( 'hudson.model.Cause$UpstreamCause' ) && d[ "upstreamBuild" ].to_s == upstream_build_id.to_s downstream_job_url.push(child[ "url" ]) break end end end end end end #Stop all the downstream jobs #http: //<Jenkins_URL>/job/<Job_Name>/<Build_Number>/stop downstream_job_url.each do |ds_url| puts "#{ds_url}stop" response = HTTParty.post( "#{ds_url}stop" , basic_auth: auth) puts response.code unless response.nil? end EORUBY

          It is so annoying to have to abort all child jobs everytime I abort a parent job. Now I started to search for a solution and ended up with this 7 year old bug report. Why isn't this fixed or at least added as an additional option as requested? Is it too complicated?

          I voted for this ticket now and hope to see a solution during my lifetime.

          Until then I'm going to try sridgma's workaround.

          Hermann Boeken added a comment - It is so annoying to have to abort all child jobs everytime I abort a parent job. Now I started to search for a solution and ended up with this 7 year old bug report. Why isn't this fixed or at least added as an additional option as requested? Is it too complicated? I voted for this ticket now and hope to see a solution during my lifetime. Until then I'm going to try sridgma 's workaround.

          Why isn't this fixed or at least added as an additional option as requested?

           

          The PR to solve this is pending for a long time, see https://github.com/jenkinsci/parameterized-trigger-plugin/pull/104, it just never was merged

          Sebastian Schuberth added a comment - Why isn't this fixed or at least added as an additional option as requested?   The PR to solve this is pending for a long time, see https://github.com/jenkinsci/parameterized-trigger-plugin/pull/104, it just never was merged

          Meanwhile, I can share my adopted python script for aborting downstream builds automatically. Inspired by sridgma

           

          jenkins_postbuild_abort_downstream-py

          Sasha Miroshnychenko added a comment - Meanwhile, I can share my adopted python script for aborting downstream builds automatically. Inspired by sridgma   jenkins_postbuild_abort_downstream-py

          Is there any update on this? My team would be very interested in this feature request.

          Ploutarchos Spyridonos added a comment - Is there any update on this? My team would be very interested in this feature request.

          Pavel Chachotkin added a comment - - edited

          Hi huybrechts
          This improvement request was opened in 2011. 9 years have gone by since that moment.
          30 watchers, 29 votes.
          Are there any updates on this problem? Or blockers for implementation?
          We need that functionality, too.

          Pavel Chachotkin added a comment - - edited Hi  huybrechts This improvement request was opened in 2011. 9 years have gone by since that moment. 30 watchers, 29 votes. Are there any updates on this problem? Or blockers for implementation? We need that functionality, too.

          Hello bahdad, can you please add some information on how to use your adopted python script?

          Hermann Boeken added a comment - Hello bahdad , can you please add some information on how to use your adopted python script?

            huybrechts huybrechts
            nicolas_godelu Nicolas Godelu
            Votes:
            31 Vote for this issue
            Watchers:
            33 Start watching this issue

              Created:
              Updated: