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