Persist Ci::JobRuntimeEnvironment when a build has suspend options
- !244035 (merged) — schema + read-side groundwork
- This MR — persist
Ci::BuildRuntimeEnvironmenton suspend - !247561 (merged) — record the runner machine assignment when a build starts running
- !247562 (merged) — resolve
runner_machine_idwhen queuing a suspend/resume build - !247563 — consume the routed runner machine when assigning jobs
- !247564 — retire the old
environment_keystring-matching routing mechanism
What does this MR do and why?
With this MR, Gitlab::Ci::Pipeline::Chain::Create bulk-inserts a Ci::JobRuntimeEnvironment row for each build carrying suspend options, resolving environment_key to an existing Ci::RuntimeEnvironment via find_by_key_and_project (from Route resumed CI jobs to correct runner machine (!244035 - merged) • Ashvin Sharma • 19.3) where a resume target already exists. This is gated by the FF ci_suspendable_environment_runner_routing which uses project as its actor.
Why now, before anything reads these rows: creating the record is the one piece every downstream MR in this stack needs (recording the runner machine assignment, resolving it at queue time, consuming it when assigning jobs). Landing it on its own lets it be reviewed and load-tested (bulk insert path, partitioning) independently of any behavior change.
Part of routing resumed builds to the runner machine that holds their suspended environment Resumable Jobs for CI and Agent Sessions (gitlab-org#21159).
References
Depends on !244035 (merged) (schema + find_by_key_and_project/runner_machine_id_for lookup helpers).
Issue: Resumable Jobs for CI and Agent Sessions (gitlab-org#21159)
Blueprint: Add blueprint for suspendable environments (gitlab-com/content-sites/handbook!18954 - merged)
How to set up and validate locally
Feature.enable(:ci_suspendable_environment_runner_routing)
suffix = SecureRandom.hex(6)
user = FactoryBot.create(:user, username: "bre-verify-#{suffix}", email: "bre-verify-#{suffix}@example.com")
project = FactoryBot.create(:project, namespace: user.namespace, creator: user)
project.add_maintainer(user)
project.create_repository
ci_yaml = { job: { script: 'echo hi' } }.deep_stringify_keys.to_yaml
project.repository.create_file(user, '.gitlab-ci.yml', ci_yaml, message: 'Add CI config', branch_name: project.default_branch_or_main)
response = Ci::CreatePipelineService.new(project, user, ref: project.default_branch_or_main).execute(
:push, content: ci_yaml, suspend_options: { suspend_on_success: true }
)
pipeline = response.payload
build = pipeline.builds.first
bre = build.job_runtime_environment
puts "BRE row exists: #{bre.present?} (expect true)"
puts "suspend_on_success: #{bre&.suspend_on_success.inspect} (expect true)"
puts "suspend_on_failure: #{bre&.suspend_on_failure.inspect} (expect false)"
puts "runtime_environment_id: #{bre&.runtime_environment_id.inspect} (expect nil, no existing environment to resume)"
project.destroy
user.destroyMR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.