Persist Ci::JobRuntimeEnvironment when a build has suspend options

  1. !244035 (merged) — schema + read-side groundwork
  2. This MR — persist Ci::BuildRuntimeEnvironment on suspend
  3. !247561 (merged) — record the runner machine assignment when a build starts running
  4. !247562 (merged) — resolve runner_machine_id when queuing a suspend/resume build
  5. !247563 — consume the routed runner machine when assigning jobs
  6. !247564 — retire the old environment_key string-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.destroy

MR 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.

Edited by Ashvin Sharma

Merge request reports

Loading
Loading