Commit aa14df2
authored
feat(speculate): hold speculating until the batch can be sent to merge (#586)
## Summary
### Why?
A request's trail read `batched → speculating → speculated → speculating
→ speculated → landing → landed`, and the repeats looked like the
pipeline regressing. They were not a reporting glitch:
`RequestStatusSpeculated` meant "a build passed on a path still
consistent with how its dependencies are resolving", so it was published
while the batch was still blocked, and `reportSpeculation` republished
`speculating` whenever a dependency later resolved against that path's
guess. Each extra pair was one speculative guess that passed and was
then invalidated.
That made `speculated` a per-path, provisional fact wearing a status —
the exact shape `RequestEvent` exists for. A batch is not done
speculating until it can be sent to merge; waiting on dependencies is
still speculating.
### What?
Two events join the vocabulary. `waiting` records that a path passed and
the batch has nothing of its own left to run; `invalidated` records that
a dependency resolved against the guess that path made. Both are
occurrence-keyed on the path ID, so a passed path re-observed across
runs collapses to one entry.
`waiting` is gated on `outcomeWait` rather than on merely holding a live
passed path. A merge is decided on that same predicate — `mergeablePath`
implies `livePassedPath` — so an ungated report would claim a wait on
every request that merges straight through. `reportSpeculation` moves
below `decide` to see the outcome; both it and `decide` only read, so
the reorder observes nothing different.
`speculated` stays a status but now means speculation finished,
published from `dispatchMerge` once the batch is cleared to merge. It
goes ahead of the dispatch because the merge stage publishes `landing`
as its first act on receiving one, and both statuses are non-terminal —
so a `speculated` sent afterwards could carry the later timestamp and
beat `landing` in the summary.
The `hadPassed && !hasPassed` republish of `speculating` is gone. The
status never leaves, so there is nothing to republish, and the
oscillation goes with it.
One trade-off worth naming: `speculated` is now near-instantaneous, so
"is this batch blocked on dependencies?" is answerable from the latest
event rather than from the status.
The second commit adds the end-to-end coverage this had been missing.
Nothing in `test/integration/` touches the speculate pipeline — the
orchestrator integration suite is `TestPingAPI` and nothing else — and
the e2e happy path has no dependencies, so it never speculates across
one. `e2e-respeculate-queue` is registered in the gateway's queue list
and deliberately takes no profile of its own: falling through to the
baseline is what gives it the `all` analyzer, which serializes the queue
so a second request becomes a batch depending on the first.
The new test forces the wait rather than racing it. Batch IDs come from
a per-queue counter as `<queue>/batch/<n>`, so on a fresh queue the
leader is `batch/1`, and the build topic partitions by batch — closing
the consumer gate on that partition before anything is published holds
the leader's build and nothing else. The follower reaches a passed path
while its dependency is still outstanding, reports `waiting`, and is
asserted to still be `speculating`. Releasing the gate fails the leader,
and the follower re-plans and lands with `speculating` and `speculated`
recorded exactly once each.
`invalidated` is deliberately not asserted end to end. A passed path
stops occupying build budget, so by the time the leader fails the
follower has usually funded the other side of the guess as well; it
never loses its last live passed path, which is the state `invalidated`
reports. Forcing that end to end would mean starving the queue's budget,
which cannot be done without also starving the follower's first build. A
unit test covers the case e2e cannot reach deterministically: a
dependency turning terminal in the same run that walks the head resting
on it, so the break is seen by a later generation of the finalize loop
rather than by the read.
A third commit adapts `TestDependentBatch_IsWokenByTheMergeAhead`, which
#576 added to main after this branch was cut. It parks the lead batch's
merge behind a closed gate, waits for the dependent to reach
`speculated`, and only then opens the gate — an ordering that encodes
the old meaning of `speculated`, which a batch could reach while its
dependency was still outstanding. Under this change the dependent rests
at `speculating` instead, so the test waited for a status that could not
arrive until it opened the gate, and did not open the gate until it
arrived. It now waits for the `waiting` event: the same fact it was
reaching for, expressed as the signal that carries it, and reachable
while the lead is still parked. The gate still opens next and both
requests are still asserted to land, so the wake-up remains attributable
to the fan-out alone.
## Test Plan
✅ `bazel test //submitqueue/... //platform/... //service/...` — 73 tests
pass
✅ `bazel test //test/e2e/...` — 3/3 pass, including the new scenario
✅ `make lint`, `make check-gazelle`, `make check-tidy`, `make
check-mocks`
Re-verified after rebasing onto main at `42d1cb72`: `bazel test
//submitqueue/... //platform/...` — 69 tests pass; `bazel test
//test/e2e/submitqueue` — passes in 120s, against the 300s timeout it
hit before the third commit.
The two `reportSpeculation` tests now assert events. New unit coverage:
a merging head reports `speculated` and no wait (the gate's regression
test); `speculated` is published before the `TopicKeyMerge` dispatch;
and the same-run cascade reports `invalidated`.
`TestLand_HappyPath_ReachesLanded` needs no change: `speculating →
speculated → landing → landed` still holds as an ordered subsequence,
now for a different reason and at a different point in time.
## Issue
Closes https://linear.app/uber/issue/CODEM-443
## Stack
1. #585
1. @ #5861 parent 42d1cb7 commit aa14df2
6 files changed
Lines changed: 271 additions & 61 deletions
File tree
- service/submitqueue/gateway/server
- submitqueue
- entity
- orchestrator/controller/speculate
- test/e2e/submitqueue
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
23 | 23 | | |
24 | 24 | | |
25 | 25 | | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
54 | 54 | | |
55 | 55 | | |
56 | 56 | | |
57 | | - | |
| 57 | + | |
| 58 | + | |
58 | 59 | | |
59 | 60 | | |
60 | | - | |
61 | | - | |
| 61 | + | |
| 62 | + | |
62 | 63 | | |
63 | 64 | | |
64 | 65 | | |
| |||
84 | 85 | | |
85 | 86 | | |
86 | 87 | | |
87 | | - | |
88 | | - | |
89 | | - | |
90 | | - | |
91 | | - | |
92 | | - | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
93 | 94 | | |
94 | | - | |
95 | | - | |
96 | | - | |
97 | | - | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
98 | 99 | | |
99 | 100 | | |
100 | 101 | | |
| |||
107 | 108 | | |
108 | 109 | | |
109 | 110 | | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
110 | 119 | | |
111 | 120 | | |
112 | 121 | | |
| |||
Lines changed: 33 additions & 35 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
83 | 83 | | |
84 | 84 | | |
85 | 85 | | |
86 | | - | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
87 | 89 | | |
88 | 90 | | |
89 | 91 | | |
90 | | - | |
91 | 92 | | |
92 | 93 | | |
93 | 94 | | |
| |||
129 | 130 | | |
130 | 131 | | |
131 | 132 | | |
132 | | - | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
133 | 136 | | |
134 | | - | |
135 | | - | |
136 | | - | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
137 | 140 | | |
138 | | - | |
139 | | - | |
140 | | - | |
141 | | - | |
142 | | - | |
143 | | - | |
144 | | - | |
145 | | - | |
146 | | - | |
147 | | - | |
148 | | - | |
149 | | - | |
150 | | - | |
151 | | - | |
152 | | - | |
153 | | - | |
154 | | - | |
155 | | - | |
156 | | - | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
157 | 144 | | |
158 | 145 | | |
159 | 146 | | |
160 | 147 | | |
161 | 148 | | |
162 | 149 | | |
163 | 150 | | |
| 151 | + | |
164 | 152 | | |
165 | 153 | | |
166 | 154 | | |
167 | | - | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
168 | 158 | | |
169 | | - | |
170 | | - | |
171 | | - | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
172 | 162 | | |
173 | 163 | | |
174 | 164 | | |
175 | 165 | | |
176 | | - | |
177 | | - | |
| 166 | + | |
| 167 | + | |
178 | 168 | | |
179 | 169 | | |
180 | 170 | | |
| |||
183 | 173 | | |
184 | 174 | | |
185 | 175 | | |
186 | | - | |
| 176 | + | |
187 | 177 | | |
188 | 178 | | |
189 | 179 | | |
| |||
369 | 359 | | |
370 | 360 | | |
371 | 361 | | |
372 | | - | |
373 | | - | |
374 | | - | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
375 | 366 | | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
376 | 374 | | |
377 | 375 | | |
378 | 376 | | |
| |||
Lines changed: 110 additions & 9 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1406 | 1406 | | |
1407 | 1407 | | |
1408 | 1408 | | |
1409 | | - | |
1410 | | - | |
1411 | | - | |
1412 | | - | |
| 1409 | + | |
| 1410 | + | |
| 1411 | + | |
1413 | 1412 | | |
1414 | 1413 | | |
1415 | 1414 | | |
| |||
1434 | 1433 | | |
1435 | 1434 | | |
1436 | 1435 | | |
1437 | | - | |
| 1436 | + | |
| 1437 | + | |
1438 | 1438 | | |
1439 | 1439 | | |
1440 | 1440 | | |
1441 | 1441 | | |
1442 | 1442 | | |
1443 | | - | |
1444 | | - | |
1445 | | - | |
| 1443 | + | |
| 1444 | + | |
1446 | 1445 | | |
1447 | 1446 | | |
1448 | 1447 | | |
| |||
1465 | 1464 | | |
1466 | 1465 | | |
1467 | 1466 | | |
1468 | | - | |
| 1467 | + | |
| 1468 | + | |
1469 | 1469 | | |
1470 | 1470 | | |
| 1471 | + | |
| 1472 | + | |
| 1473 | + | |
| 1474 | + | |
| 1475 | + | |
| 1476 | + | |
| 1477 | + | |
| 1478 | + | |
| 1479 | + | |
| 1480 | + | |
| 1481 | + | |
| 1482 | + | |
| 1483 | + | |
| 1484 | + | |
| 1485 | + | |
| 1486 | + | |
| 1487 | + | |
| 1488 | + | |
| 1489 | + | |
| 1490 | + | |
| 1491 | + | |
| 1492 | + | |
| 1493 | + | |
| 1494 | + | |
| 1495 | + | |
| 1496 | + | |
| 1497 | + | |
| 1498 | + | |
| 1499 | + | |
| 1500 | + | |
| 1501 | + | |
| 1502 | + | |
| 1503 | + | |
| 1504 | + | |
| 1505 | + | |
| 1506 | + | |
| 1507 | + | |
| 1508 | + | |
| 1509 | + | |
| 1510 | + | |
| 1511 | + | |
| 1512 | + | |
| 1513 | + | |
| 1514 | + | |
| 1515 | + | |
| 1516 | + | |
| 1517 | + | |
| 1518 | + | |
| 1519 | + | |
| 1520 | + | |
| 1521 | + | |
| 1522 | + | |
| 1523 | + | |
| 1524 | + | |
| 1525 | + | |
| 1526 | + | |
| 1527 | + | |
| 1528 | + | |
| 1529 | + | |
| 1530 | + | |
| 1531 | + | |
| 1532 | + | |
| 1533 | + | |
| 1534 | + | |
| 1535 | + | |
| 1536 | + | |
| 1537 | + | |
| 1538 | + | |
| 1539 | + | |
| 1540 | + | |
| 1541 | + | |
| 1542 | + | |
| 1543 | + | |
| 1544 | + | |
| 1545 | + | |
| 1546 | + | |
| 1547 | + | |
| 1548 | + | |
| 1549 | + | |
| 1550 | + | |
| 1551 | + | |
| 1552 | + | |
| 1553 | + | |
| 1554 | + | |
| 1555 | + | |
| 1556 | + | |
| 1557 | + | |
| 1558 | + | |
| 1559 | + | |
| 1560 | + | |
| 1561 | + | |
| 1562 | + | |
| 1563 | + | |
| 1564 | + | |
| 1565 | + | |
| 1566 | + | |
| 1567 | + | |
| 1568 | + | |
| 1569 | + | |
| 1570 | + | |
| 1571 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
207 | 207 | | |
208 | 208 | | |
209 | 209 | | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
210 | 250 | | |
211 | 251 | | |
212 | 252 | | |
| |||
0 commit comments