Commit a0d6532
authored
fix(extension): forward the per-queue Config down to every impl (#553)
## Summary
### Why?
Per-queue extensions are resolved through a `Factory` contract —
`For(cfg Config) (Impl, error)`, where `Config` carries the queue name.
The controllers hold up their end: `build.go:233` and
`buildsignal.go:183` both call
`c.buildRunners.For(buildrunner.Config{QueueName: batch.Queue})`.
The wiring layer dropped it. In
`service/submitqueue/orchestrator/server/profiles.go`, `Profile` held
built extension **instances** for ChangeProvider, BuildRunner, Analyzer,
Scorer and Speculator. Only `Storage` held a `Factory`. So the two ends
of the seam looked like this:
```go
return p.For(c.QueueName).Storage.For(c) // forwards cfg onward
return p.For(c.QueueName).BuildRunner, nil // cfg is a map key, then dropped
```
An implementation's queue name was therefore fixed at construction. For
queues listed in `byQueue` you could hand-copy the name into each
profile. For `defaultProfile` you could not: one instance serves every
queue without an explicit entry, so it can only ever carry one queue
name — or none.
The visible symptom is the Buildkite and GitHub Actions build runners,
which read `cfg.QueueName` to emit `SQ_QUEUE` / `sq_queue` for the
pipeline script. Both have zero non-test callers, so nothing ever
exercised the path and nothing caught the gap.
### What?
**The seam.** Every `Profile` field is now a `Factory`, and each
`XFactory()` resolves the profile by name and then forwards the whole
`Config` into it — the same second `For(c)` that `Storage` already used.
Implementations are built per resolution, which is what
`counterFactory.For` already does for the MySQL counter; anything
expensive and queue-independent (the resolver, the metrics scope, the
change provider's HTTP clients) is still built once in `newProfiles`.
`newChangeProvider` becomes `newChangeProviderFactory`, splitting HTTP
client construction from the per-queue provider that wraps it.
`withSpeculator` becomes a lazy closure that resolves the profile's
scorer at the queue the speculator itself was asked for, so the fix
reaches one level down. That introduces a real error path where a struct
field read could not fail; it is propagated rather than yielding a
speculator over a nil scorer. `ScorerFactory()` is added for symmetry —
the scorer was previously reachable only through `withSpeculator`.
**The implementations.** Every impl belonging to an extension that has a
`Config`+`Factory` pair now receives it: the conflict analyzers, the
scorers, the validators, the change providers, the merge checkers, the
fake build runners, the standard speculator, Stovepipe's two fakes, and
Runway's `noop` and `fake` mergers. Impls with an existing `Params`
struct gain a `Config` field, matching the Buildkite precedent; the rest
take `cfg` as a leading positional parameter.
Three decisions worth a reviewer's attention:
- **`bestfirst` and `sticky` are untouched.** Only `speculator` declares
a `Config` and a `Factory`; `generator` and `allocator` declare neither.
They are composition internals rather than per-queue seams, so giving
them a `Config` would have meant inventing two types that nothing reads.
- **Runway's mergers are stateful by design.** `fakeMergerFactory`
shared one instance so its `atomic.Uint64` revision-id counter stayed
unique, and `gitMergerFactory` shares one checkout. Building one per
queue would have broken both. The counter moves to the host factory and
is injected, which keeps ids unique process-wide while letting each
merger carry its own queue identity. This also fixes an existing quirk
in `noopMergerFactory`, which already built a fresh merger — and
therefore a fresh counter — on every resolution. `gitMergerFactory`
still shares one instance and is now the only merger factory that does
not forward its `Config`, with a comment recording why.
- **`validatorfake.NewFactory` moves into the wiring.** `CLAUDE.md`
reserves extension packages for contracts and implementations — deciding
which impl serves which queue is host policy — so it is replaced by a
`validatorFactory` adapter in the orchestrator wiring.
Four implementations deliberately still take no `Config`: `submitqueue`,
`stovepipe` and `platform`'s MySQL storage/counter backends already take
the queue name as a plain string and the host adapters bridge to it, and
`merger/git` is the shared-checkout exception above.
The change is split into five commits — four mechanical per-family ones,
then the wiring rewrite that actually fixes the bug — so it can be
reviewed and bisected a family at a time.
## Test Plan
✅ `make test` — 96/96, including three new cases in `profiles_test.go`
✅ `make build` — all four service binaries
✅ `bazel test //test/integration/...` — 8/8
✅ `bazel test //test/e2e/...` — 3/3
✅ `make lint`, `make check-gazelle`, `make check-tidy`, `make
check-mocks` — all clean
Mutation-checked the regression guard: reverting a single `For(c)` back
to `For(Config{})` fails `TestProfilesForwardQueueNameToFactories` for
both the listed-queue and default-profile cases. That test is the thing
that was missing — it asserts the `Config` survives the profile lookup,
which is precisely what no test covered before.
The implementation half was already covered: `buildkite_test.go:109` and
`githubactions_test.go:123` assert the queue name reaches the wire.
Together the two halves cover the full path from controller to CI
request.
Two pre-existing issues left untouched, both unrelated to this change:
`go test ./runway/extension/merger/git/...` fails outside Bazel on a
machine without a hermetic git toolchain (it passes under `bazel test`),
and `go vet` reports `copylocks` on protobuf `MessageState` in the
mergesignal tests.1 parent 9a1cafa commit a0d6532
51 files changed
Lines changed: 648 additions & 268 deletions
File tree
- runway/extension/merger
- fake
- noop
- service
- runway/server
- stovepipe/server
- submitqueue/orchestrator/server
- stovepipe/extension
- buildrunner/fake
- sourcecontrol/fake
- submitqueue
- extension
- buildrunner/fake
- changeprovider
- fake
- github
- phabricator
- routing
- conflict
- all
- fake
- fileoverlap
- none
- mergechecker
- fake
- github
- scorer
- composite
- fake
- heuristic
- speculation/speculator/standard
- validator
- composite
- fake
- orchestrator/controller/batch
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
51 | 51 | | |
52 | 52 | | |
53 | 53 | | |
54 | | - | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
55 | 60 | | |
56 | 61 | | |
57 | | - | |
58 | | - | |
59 | | - | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
60 | 69 | | |
61 | 70 | | |
62 | 71 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
16 | 16 | | |
17 | 17 | | |
18 | 18 | | |
| 19 | + | |
19 | 20 | | |
20 | 21 | | |
21 | 22 | | |
| |||
27 | 28 | | |
28 | 29 | | |
29 | 30 | | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
30 | 34 | | |
31 | 35 | | |
32 | 36 | | |
| |||
54 | 58 | | |
55 | 59 | | |
56 | 60 | | |
57 | | - | |
| 61 | + | |
58 | 62 | | |
59 | 63 | | |
60 | 64 | | |
| |||
67 | 71 | | |
68 | 72 | | |
69 | 73 | | |
70 | | - | |
| 74 | + | |
71 | 75 | | |
72 | 76 | | |
73 | 77 | | |
| |||
102 | 106 | | |
103 | 107 | | |
104 | 108 | | |
105 | | - | |
| 109 | + | |
106 | 110 | | |
107 | 111 | | |
108 | | - | |
| 112 | + | |
109 | 113 | | |
110 | 114 | | |
111 | 115 | | |
| |||
129 | 133 | | |
130 | 134 | | |
131 | 135 | | |
132 | | - | |
| 136 | + | |
133 | 137 | | |
134 | 138 | | |
135 | 139 | | |
| |||
144 | 148 | | |
145 | 149 | | |
146 | 150 | | |
147 | | - | |
| 151 | + | |
148 | 152 | | |
149 | 153 | | |
150 | 154 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
21 | 21 | | |
22 | 22 | | |
23 | 23 | | |
| 24 | + | |
24 | 25 | | |
25 | 26 | | |
26 | 27 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
31 | 31 | | |
32 | 32 | | |
33 | 33 | | |
34 | | - | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
35 | 40 | | |
36 | 41 | | |
37 | | - | |
38 | | - | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
39 | 48 | | |
40 | 49 | | |
41 | 50 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
16 | 16 | | |
17 | 17 | | |
18 | 18 | | |
| 19 | + | |
19 | 20 | | |
20 | 21 | | |
| 22 | + | |
| 23 | + | |
21 | 24 | | |
22 | 25 | | |
23 | 26 | | |
| |||
26 | 29 | | |
27 | 30 | | |
28 | 31 | | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
29 | 35 | | |
30 | 36 | | |
31 | 37 | | |
| |||
46 | 52 | | |
47 | 53 | | |
48 | 54 | | |
49 | | - | |
| 55 | + | |
50 | 56 | | |
51 | 57 | | |
52 | 58 | | |
| |||
62 | 68 | | |
63 | 69 | | |
64 | 70 | | |
65 | | - | |
| 71 | + | |
66 | 72 | | |
67 | 73 | | |
68 | 74 | | |
| |||
80 | 86 | | |
81 | 87 | | |
82 | 88 | | |
83 | | - | |
| 89 | + | |
84 | 90 | | |
85 | 91 | | |
86 | 92 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
25 | 25 | | |
26 | 26 | | |
27 | 27 | | |
| 28 | + | |
28 | 29 | | |
29 | 30 | | |
30 | 31 | | |
| |||
314 | 315 | | |
315 | 316 | | |
316 | 317 | | |
317 | | - | |
| 318 | + | |
318 | 319 | | |
319 | 320 | | |
320 | | - | |
| 321 | + | |
321 | 322 | | |
322 | 323 | | |
323 | 324 | | |
| |||
327 | 328 | | |
328 | 329 | | |
329 | 330 | | |
330 | | - | |
| 331 | + | |
331 | 332 | | |
332 | 333 | | |
333 | 334 | | |
| |||
370 | 371 | | |
371 | 372 | | |
372 | 373 | | |
373 | | - | |
| 374 | + | |
| 375 | + | |
374 | 376 | | |
375 | 377 | | |
376 | 378 | | |
| |||
380 | 382 | | |
381 | 383 | | |
382 | 384 | | |
383 | | - | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
| 390 | + | |
384 | 391 | | |
385 | | - | |
386 | | - | |
| 392 | + | |
| 393 | + | |
387 | 394 | | |
388 | 395 | | |
389 | | - | |
390 | | - | |
| 396 | + | |
| 397 | + | |
| 398 | + | |
391 | 399 | | |
392 | | - | |
| 400 | + | |
393 | 401 | | |
394 | 402 | | |
395 | | - | |
396 | | - | |
| 403 | + | |
| 404 | + | |
397 | 405 | | |
398 | 406 | | |
399 | 407 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
133 | 133 | | |
134 | 134 | | |
135 | 135 | | |
136 | | - | |
| 136 | + | |
137 | 137 | | |
138 | 138 | | |
139 | | - | |
140 | | - | |
141 | | - | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
142 | 142 | | |
143 | 143 | | |
144 | | - | |
145 | | - | |
| 144 | + | |
| 145 | + | |
146 | 146 | | |
147 | 147 | | |
148 | 148 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
| 1 | + | |
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
| |||
49 | 49 | | |
50 | 50 | | |
51 | 51 | | |
| 52 | + | |
52 | 53 | | |
53 | 54 | | |
54 | 55 | | |
| |||
87 | 88 | | |
88 | 89 | | |
89 | 90 | | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
0 commit comments