Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cancel_pending_pipelines.rb « chain « pipeline « ci « gitlab « lib - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 07a3aff18625a4da94a66ad847862e4a50f5159a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# frozen_string_literal: true

module Gitlab
  module Ci
    module Pipeline
      module Chain
        class CancelPendingPipelines < Chain::Base
          include Chain::Helpers

          BATCH_SIZE = 25

          # rubocop: disable CodeReuse/ActiveRecord
          def perform!
            ff_enabled = Feature.enabled?(:ci_skip_auto_cancelation_on_child_pipelines, project)
            return if ff_enabled && pipeline.parent_pipeline? # skip if child pipeline
            return unless project.auto_cancel_pending_pipelines?

            Gitlab::OptimisticLocking.retry_lock(auto_cancelable_pipelines(ff_enabled), name: 'cancel_pending_pipelines') do |cancelables|
              cancelables.select(:id).each_batch(of: BATCH_SIZE) do |cancelables_batch|
                auto_cancel_interruptible_pipelines(cancelables_batch.ids)
              end
            end
          end
          # rubocop: enable CodeReuse/ActiveRecord

          def break?
            false
          end

          private

          def auto_cancelable_pipelines(ff_enabled)
            relation = project.all_pipelines
              .created_after(1.week.ago)
              .ci_and_parent_sources
              .for_ref(pipeline.ref)
              .where_not_sha(project.commit(pipeline.ref).try(:id))
              .alive_or_scheduled

            if ff_enabled
              relation.id_not_in(pipeline.id)
            else
              relation.id_not_in(pipeline.same_family_pipeline_ids)
            end
          end

          def auto_cancel_interruptible_pipelines(pipeline_ids)
            ::Ci::Pipeline
              .id_in(pipeline_ids)
              .with_only_interruptible_builds
              .each do |cancelable_pipeline|
                Gitlab::AppLogger.info(
                  class: self.class.name,
                  message: "Pipeline #{pipeline.id} auto-canceling pipeline #{cancelable_pipeline.id}",
                  canceled_pipeline_id: cancelable_pipeline.id,
                  canceled_by_pipeline_id: pipeline.id,
                  canceled_by_pipeline_source: pipeline.source
                )

                # cascade_to_children not needed because we iterate through descendants here
                cancelable_pipeline.cancel_running(
                  auto_canceled_by_pipeline_id: pipeline.id,
                  cascade_to_children: false
                )
              end
          end
        end
      end
    end
  end
end