You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(buildrunner): drop per-call queueName, add Factory
## Summary
### Why?
`BuildRunner.Trigger` took a `queueName` argument that selected the
runner-specific job configuration on every call. That put queue routing
on the hot path and on a single verb, leaving `Status` and `Cancel` to
rediscover the queue from the build ID. A runner's connection pools,
caches, and job defaults are all keyed to one queue's configuration, so
the queue belongs at construction time, not per call.
### What?
- Drop `queueName` from `BuildRunner.Trigger`; the verbs now speak only
in builds and changes.
- Add a `Factory` interface (`New(cfg Config) (BuildRunner, error)`) and
a placeholder `Config` struct. A runner is bound to one queue's job
configuration at construction. `Config` is intentionally empty for now
— its fields (queue/job selection plus backend settings) land with the
first real backend.
- noop: add `NewFactory()` + factory `New`; keep `New()` so existing
wiring is untouched.
- build controller: call site drops `batch.Queue`.
- Update the build-runner RFC (new Construction section, Interface and
Lifecycle updates), the extension README, and regenerate the mock.
## Test Plan
✅ `make mocks`, `make gazelle`, `make fmt`
✅ `bazel build //...`
✅ `bazel test //extension/buildrunner/... //orchestrator/controller/build/...`
Copy file name to clipboardExpand all lines: doc/rfc/build-runner.md
+17-2Lines changed: 17 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -38,12 +38,27 @@ The build stage needs a vendor-agnostic abstraction for talking to a Build Runne
38
38
39
39
`BuildRunner` exposes three verbs, all keyed by a build identifier (`entity.BuildID`):
40
40
41
-
-**`Trigger`** — submit a build for a queue, given the ordered `base` and `head` change sets plus a free-form metadata map; returns the new build's ID. Runner-side work is asynchronous.
41
+
-**`Trigger`** — submit a build given the ordered `base` and `head` change sets plus a free-form metadata map; returns the new build's ID. Runner-side work is asynchronous.
42
42
-**`Status`** — fetch the current `BuildStatus` and runner-defined metadata for a build; MAY round-trip to the runner.
43
43
-**`Cancel`** — request cancellation; returns once the request reaches the runner, not once the build stops.
44
44
45
45
See `extension/buildrunner/build_runner.go` for the exact Go signatures. The sections below record why the contract is shaped this way.
46
46
47
+
### Construction: a Factory, queue bound at build time
48
+
49
+
A `BuildRunner` does not take a queue selector on any verb. The queue whose job configuration a runner uses is fixed when the runner is constructed, and runners are constructed by a `Factory`.
50
+
51
+
-**`Factory`** — produces `BuildRunner` instances from a `Config`. A controller that drives builds for several queues holds one `Factory` and obtains one `BuildRunner` per queue.
52
+
-**`Config`** — the per-runner configuration the factory binds in: the queue's job selection plus any backend-specific settings (endpoints, credentials, defaults). The schema is backend-defined and lands with the first real implementation; today it is an intentionally empty placeholder so the `Factory` contract can stabilize ahead of it.
53
+
54
+
Why bind the queue at construction rather than pass it per call:
55
+
56
+
- A runner's connection pool, caches, and job defaults are all keyed to one queue's configuration. Passing the queue per call would force every implementation to re-resolve that configuration on the hot path, or to maintain an internal queue→config map the factory already expresses cleanly.
57
+
- It keeps the per-call verbs (`Trigger`, `Status`, `Cancel`) free of routing concerns — they speak only in builds and changes.
58
+
- It matches the rest of the extension family, whose implementations are long-lived singletons bound to their configuration at construction.
59
+
60
+
Rejected: a `queueName` argument on `Trigger`. It put routing on the hot path and on a single verb, leaving `Status` and `Cancel` to rediscover the queue from the build ID. Moving the selection into `Config` makes one runner mean one queue everywhere.
61
+
47
62
### Trigger: base + head
48
63
49
64
`Trigger` takes two ordered lists of changes and a free-form metadata map:
@@ -125,7 +140,7 @@ Rejected: long-polling on `Status`. Not every backend supports efficient server-
125
140
126
141
### Lifecycle
127
142
128
-
Implementations are long-lived singletons bound to provider config at construction. Every method is concurrent-safe; connection pools and caches live inside the manager; anything that must survive a restart belongs in persistent storage, not the manager.
143
+
Implementations are long-lived singletons constructed by a `Factory` and bound to one queue's provider config at construction (see *Construction* above). Every method is concurrent-safe; connection pools and caches live inside the manager; anything that must survive a restart belongs in persistent storage, not the manager.
Copy file name to clipboardExpand all lines: extension/buildrunner/README.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -6,7 +6,7 @@ See [`doc/rfc/build-runner.md`](../../doc/rfc/build-runner.md) for the contract
6
6
7
7
## Adding a new backend
8
8
9
-
1. Create `extension/buildrunner/{backend}/` with a `BuildRunner` implementation bound to its runner configuration at construction.
9
+
1. Create `extension/buildrunner/{backend}/` with a `Factory` whose `New` returns a `BuildRunner`bound to one queue's job configuration. The runner verbs carry no queue selector — that selection lives in the `Config` passed to the factory.
10
10
2. Map the `base` and `head` change slices onto the backend's build primitives (apply `base`, apply `head`, validate the result).
11
11
3. Map the runner's lifecycle states down to the `BuildStatus` values: `Accepted` (accepted for execution), `Running` (executing), and the terminal `Succeeded` / `Failed` / `Cancelled`.
12
12
4. Implement internal reconnect / retry so transient failures surface as plain errors without blocking the caller.
0 commit comments