Skip to content

Model distributed runner startup as boot capabilities - #1161

Open
phinze wants to merge 1 commit into
mainfrom
phinze/mir_1690-model-distributed-runner-startup-as-boot-capabilities
Open

Model distributed runner startup as boot capabilities#1161
phinze wants to merge 1 commit into
mainfrom
phinze/mir_1690-model-distributed-runner-startup-as-boot-capabilities

Conversation

@phinze

@phinze phinze commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

#1158 exposes the runner’s startup phases as capabilities, but the standalone command would still hide them behind Runner.Start. That would make distributed startup look graph-managed while its lifecycle and readiness boundaries remained implicit.

This carries the capability model through distributed startup. Cluster access and containerd begin independently; storage and telemetry wait for cluster access; the sandbox host waits for their ready outputs; and node presence is published only after both agents are active. Telemetry now receives the coordinator-backed workload issuer before its writers start.

The shared storage-agent, sandbox-agent, and node-presence adapters live alongside the runner capabilities. Containerd’s boot adapter is shared by server and runner composition too. The CLI keeps command policy, signal handling, and the final background-task wait, while the graph owns startup rollback and reverse teardown.

Focused component and CLI tests pass, including containerd’s integration test, and repository lint is clean.

Closes MIR-1690

The standalone runner still hid cluster access, storage recovery, host
restoration, agent activation, and node readiness behind Runner.Start.
That made its graph a shallow wrapper around the lifecycle the graph was
supposed to own.

Give each runner capability its own node, matching server startup. Let
cluster access publish the remote workload issuer before telemetry starts,
and publish node presence only after both agents are active. Reconstitute
Runner afterward as a role-level handle rather than a lifecycle owner.

Move the containerd adapter alongside the component so server and runner
share daemon and client ownership without sharing composition-specific
wiring.
@coderabbitai

coderabbitai Bot commented Sep 4, 2026

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 29 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 3 included reviews currently available. Your 79 included PR review attempts over the past 7 days set your current allowance at 3 reviews per hour.

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: a2f364f2-7d4c-43fd-b665-818f41dd43bc

📥 Commits

Reviewing files that changed from the base of the PR and between 69fe9be and f39c652.

📒 Files selected for processing (26)
  • cli/commands/runner_start.go
  • components/containerd/boot.go
  • components/distributedrunner/boot_cluster_access.go
  • components/distributedrunner/boot_containerd.go
  • components/distributedrunner/boot_node_storage.go
  • components/distributedrunner/boot_sandbox_host.go
  • components/distributedrunner/boot_telemetry.go
  • components/distributedrunner/boot_telemetry_test.go
  • components/distributedrunner/runtime.go
  • components/distributedrunner/startup.go
  • components/distributedrunner/startup_test.go
  • components/runner/boot.go
  • components/server/boot_app_metrics.go
  • components/server/boot_buildkit.go
  • components/server/boot_containerd.go
  • components/server/boot_etcd.go
  • components/server/boot_node_presence.go
  • components/server/boot_node_storage.go
  • components/server/boot_sandbox_agent.go
  • components/server/boot_sandbox_host.go
  • components/server/boot_storage_agent.go
  • components/server/boot_victorialogs.go
  • components/server/boot_victoriametrics.go
  • components/server/boot_work_admission_test.go
  • components/server/runtime.go
  • components/server/startup.go

Comment @coderabbitai help to get the list of available commands.

@miren-code-agent miren-code-agent Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🍪 biscuit: ✅ ready to merge — auto-review, non-blocking

This is a draft PR. The change is structurally sound and I'm comfortable recommending it graduate to human review.

What it does. The PR lifts the distributed-runner's flat startup sequence in runner_start.go into a proper boot graph modelled after the existing components/server pattern. ~300 lines of imperative init code give way to a set of typed boot nodes (clusterAccess → nodeStorage + telemetry → sandboxHost → storageAgent + sandboxAgent → nodePresence) wired through the pkg/boot graph. components/containerd gains its own Boot node reusable by both the server and the distributed runner, eliminating the components/server/boot_containerd.go file entirely.

What I verified.

  • The dependency ordering in startup.go matches what the old imperative code did. The graph's failure cleanup path in runtime.Start correctly calls runtime.Stop on any partial start, which propagates to each boot node's stop().
  • The b.client.HTTP dereferences in boot_telemetry.go lines 93 and 107 are both reachable only when b.client != nil (the outer guard at line 70 sets it when either address is non-empty, and the inner checks are strict subsets of that condition). No nil dereference.
  • stop() in containerd/boot.go is called by the graph's cleanup path even on startup failure (via runtime.Stop in the Start error branch). b.result.Client is set before the readiness check, but stop() closes it, so there's no leak.
  • stopTimeout=0 in the distributed-runner's storage/sandbox/presence boot calls defers to the graph's outer timeout rather than cutting immediately — the pkg/boot/lifecycle.go code only adds a timeout when stopTimeout > 0.
  • The resolveRunnerContainerd helper correctly returns ("", "", nil) for an external socket, and containerdBootConfig in boot_containerd.go routes to ExternalBootConfig in that case. The redundant path reconstruction in EmbeddedBootConfig when binDir != "" is harmless.
  • Tests cover the graph-validates path, the cascade-failure path (containerd failure prevents sandbox host from starting), and all four telemetry configuration combinations. The stubIssuer in the test correctly exercises the token-source arm path.

One minor note. boot_containerd.go passes a socketPath into EmbeddedBootConfig that is computed by the caller as filepath.Join(options.DataPath, "containerd", "containerd.sock"), but EmbeddedBootConfig also defaults to the same path when its socketPath argument is empty. The explicit argument is harmless — just slightly redundant. Not worth blocking on.

The refactoring is clean and the server startup path is an established reference point for this pattern. The change is ready for human review.


🍪 full review note · comment /biscuit review to run biscuit again.

@phinze
phinze marked this pull request as ready for review September 4, 2026 19:29
@phinze
phinze requested a review from a team as a code owner September 4, 2026 19:29

@evanphx evanphx left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great cleanup!

tokenSource.SetIssuer(issuer)
} else if telemetryClient != nil {
ctx.Log.Error("no workload identity issuer available; telemetry cannot be shipped")
stop := func() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this a function that is just called one place rather than being down below at the call site?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants