[go: up one dir, main page]

Skip to content

Cascade parent/child pipeline cancellation

follow up from #208411 (comment 433793672)

During the discussion about canceling interruptible jobs for child pipeline @fabiopitino wrote on his comment

If it makes sense we could split this into 2 issues (1) related manually canceling the pipeline and (2) related to the interruptible jobs and auto-canceling a pipeline.

To solve (1) we need to change the definition of Ci::Pipeline#cancel_running:

  • should we cancel all the cancelable jobs in the parent pipeline and its child pipelines? - cancelable jobs are those not yet completed
  • should we cancel all the cancelable jobs in the parent pipeline and the child pipelines with strategy:depend? - does it make sense to cancel child pipelines that run detached from the parent?

this issue is to explore how should we cascade child pipeline when canceling a parent pipeline

Solution

We need to ensure that both Ci::Pipeline#cancel_running and Ci::Pipeline#auto_cancel_running cascade the cancellation to child pipelines.

diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb
index 0e55841f5fa..bf844df02b9 100644
--- a/app/models/ci/pipeline.rb
+++ b/app/models/ci/pipeline.rb
@@ -574,7 +574,7 @@ def cancel_running(retries: nil)
       commit_status_relations = [:project, :pipeline]
       ci_build_relations = [:deployment, :taggings]
 
-      retry_optimistic_lock(cancelable_statuses, retries, name: 'ci_pipeline_cancel_running') do |cancelables|
+      retry_optimistic_lock(statuses_in_self_and_descendants.cancelable, retries, name: 'ci_pipeline_cancel_running') do |cancelables|
         cancelables.find_in_batches do |batch|
           ActiveRecord::Associations::Preloader.new.preload(batch, commit_status_relations)
           ActiveRecord::Associations::Preloader.new.preload(batch.select { |job| job.is_a?(Ci::Build) }, ci_build_relations)
@@ -921,6 +921,10 @@ def builds_in_self_and_descendants
       Ci::Build.latest.where(pipeline: self_and_descendants)
     end
 
+    def statuses_in_self_and_descendants
+      CommitStatus.latest.where(pipeline: self_and_descendants)
+    end
+
     # Without using `unscoped`, caller scope is also included into the query.
     # Using `unscoped` here will be redundant after Rails 6.1
Edited by Fabio Pitino