debian-mirror-gitlab/app/services/ci/pipeline_processing/atomic_processing_service.rb

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

121 lines
3.2 KiB
Ruby
Raw Normal View History

2020-03-13 15:44:24 +05:30
# frozen_string_literal: true
module Ci
module PipelineProcessing
class AtomicProcessingService
include Gitlab::Utils::StrongMemoize
include ExclusiveLeaseGuard
attr_reader :pipeline
DEFAULT_LEASE_TIMEOUT = 1.minute
BATCH_SIZE = 20
def initialize(pipeline)
@pipeline = pipeline
@collection = AtomicProcessingService::StatusCollection.new(pipeline)
end
def execute
return unless pipeline.needs_processing?
success = try_obtain_lease { process! }
# re-schedule if we need further processing
if success && pipeline.needs_processing?
PipelineProcessWorker.perform_async(pipeline.id)
end
success
end
private
def process!
update_stages!
update_pipeline!
2023-06-20 00:43:36 +05:30
update_jobs_processed!
2020-03-13 15:44:24 +05:30
2022-03-02 08:16:31 +05:30
Ci::ExpirePipelineCacheService.new.execute(pipeline)
2022-01-26 12:08:38 +05:30
2020-03-13 15:44:24 +05:30
true
end
def update_stages!
2023-04-23 21:23:45 +05:30
pipeline.stages.ordered.each { |stage| update_stage!(stage) }
2020-03-13 15:44:24 +05:30
end
def update_stage!(stage)
2023-06-20 00:43:36 +05:30
# Update jobs for a given stage in bulk/slices
2023-04-23 21:23:45 +05:30
@collection
2023-06-20 00:43:36 +05:30
.created_job_ids_in_stage(stage.position)
.in_groups_of(BATCH_SIZE, false) { |ids| update_jobs!(ids) }
2020-03-13 15:44:24 +05:30
2023-05-27 22:25:52 +05:30
status = @collection.status_of_stage(stage.position)
2020-03-13 15:44:24 +05:30
stage.set_status(status)
end
2023-06-20 00:43:36 +05:30
def update_jobs!(ids)
created_jobs = pipeline
.current_processable_jobs
.id_in(ids)
2020-03-13 15:44:24 +05:30
.with_project_preload
.created
.ordered_by_stage
.select_with_aggregated_needs(project)
2023-06-20 00:43:36 +05:30
created_jobs.each { |job| update_job!(job) }
2020-03-13 15:44:24 +05:30
end
def update_pipeline!
pipeline.set_status(@collection.status_of_all)
end
2023-06-20 00:43:36 +05:30
def update_jobs_processed!
processing = @collection.processing_jobs
2020-03-13 15:44:24 +05:30
processing.each_slice(BATCH_SIZE) do |slice|
2023-06-20 00:43:36 +05:30
pipeline.all_jobs.match_id_and_lock_version(slice)
2020-03-13 15:44:24 +05:30
.update_as_processed!
end
end
2023-06-20 00:43:36 +05:30
def update_job!(job)
previous_status = status_of_previous_jobs(job)
# We do not continue to process the job if the previous status is not completed
2023-05-27 22:25:52 +05:30
return unless Ci::HasStatus::COMPLETED_STATUSES.include?(previous_status)
2020-03-13 15:44:24 +05:30
2023-06-20 00:43:36 +05:30
Gitlab::OptimisticLocking.retry_lock(job, name: 'atomic_processing_update_job') do |subject|
2020-03-13 15:44:24 +05:30
Ci::ProcessBuildService.new(project, subject.user)
2023-05-27 22:25:52 +05:30
.execute(subject, previous_status)
2020-03-13 15:44:24 +05:30
2023-06-20 00:43:36 +05:30
# update internal representation of job
# to make the status change of job to be taken into account during further processing
@collection.set_job_status(job.id, job.status, job.lock_version)
2020-03-13 15:44:24 +05:30
end
end
2023-06-20 00:43:36 +05:30
def status_of_previous_jobs(job)
if job.scheduling_type_dag?
# job uses DAG, get status of all dependent needs
@collection.status_of_jobs(job.aggregated_needs_names.to_a)
2020-03-13 15:44:24 +05:30
else
2023-06-20 00:43:36 +05:30
# job uses Stages, get status of prior stage
@collection.status_of_jobs_prior_to_stage(job.stage_idx.to_i)
2020-03-13 15:44:24 +05:30
end
end
def project
pipeline.project
end
def lease_key
"#{super}::pipeline_id:#{pipeline.id}"
end
def lease_timeout
DEFAULT_LEASE_TIMEOUT
end
end
end
end