Skip to content

Commit 08996ad

Browse files
committed
docs(gateway): State that status records go stale in normal operation and that readers must confirm and clean them up
1 parent 2132e39 commit 08996ad

2 files changed

Lines changed: 13 additions & 4 deletions

File tree

‎submitqueue/extension/storage/queue_request_status_store.go‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,11 @@ import (
2828
// the request summary.
2929
//
3030
// Records are advisory: the authoritative status is on the RequestSummary, and a record may
31-
// file a request under a status it has already left. Readers therefore treat a listing as a
32-
// set of candidate request IDs — they load each summary by key and classify it by its own
33-
// Status, never by the bucket the record was found in.
31+
// file a request under a status it has already left. Readers must therefore treat a listing
32+
// as a set of candidate request IDs — load each summary by key, classify the request by the
33+
// summary's own Status rather than the bucket the record was found in, and delete records
34+
// whose summary is finished or at a different status. Writers do not clean up after every
35+
// interruption, so reader cleanup is part of the contract, not an optimization.
3436
//
3537
// The interface is per-status and per-record so that any backend can implement it without
3638
// multi-key queries or batch atomicity. A request moves buckets via Put of the new record

‎submitqueue/gateway/extension/storage/mysql/schema/README.md‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,14 @@ Every table leads its primary key with `queue`: `request_summary` on `(queue, re
2626

2727
`queue_request_status` is keyed by `(queue, status, request_id)` and files each in-queue request under its public status, so "the requests of queue Q at status S" is a primary-key-prefix scan and `request_summary` keeps no secondary index. Each row carries only the request's `received_at_ms` and the `entered_at_ms` of the log that moved it into the status, enough to count and age a queue's requests by status.
2828

29-
The materializer maintains it on every log delivery, after the summary update: it files the record for the summary's current status (a no-op when present, which also repairs a delivery that failed after the update) and, when the delivery moved the summary, then deletes the record under the previous status. Accepting and terminal statuses have no record. Every write is a single-key idempotent put or delete, so the records need no multi-row transaction. A delivery that fails between the summary update and that delete leaves a stale row under the old status that no later delivery revisits, so readers treat a listing as candidate request IDs, confirm each against its summary, and may delete rows that disagree.
29+
The materializer maintains it on every status-log delivery, after the summary update: it files the record for the summary's current status (a no-op when present, which also repairs a delivery that failed after the update) and, when the delivery moved the summary, then deletes the record under the previous status. Accepting and terminal statuses have no record, and event logs, which never move the summary, write nothing. Every write is a single-key idempotent put or delete, so the records need no multi-row transaction.
30+
31+
Stale rows are a normal occurrence, not only a failure mode, and two rules bound them:
32+
33+
- Land and Cancel persist logs outside the log consumer's per-request ordering, so another writer can move the summary on and delete a status's record before a late put re-creates it. After each put the materializer re-reads the summary and deletes the record it just filed if the status has moved on; every writer updates the summary before deleting, so the re-read sees any such move.
34+
- A terminal summary deletes the request's record under every in-queue status, on every terminal delivery. That retries a failed removal and clears records stranded by earlier failed moves.
35+
36+
A record stranded by a failed move while the request is still in the queue remains until the request finishes. Readers must therefore confirm each listed request against its summary, count it only under the summary's status, and delete rows whose summary is finished or at a different status. That costs one summary read per listed row per reader per sample, which is small while queues are short but grows with queue depth and the number of reading instances.
3037

3138
The records are kept only by a storage built with `WithQueueRequestStatusRecords`, which a deployment enables once the table exists; without it, record writes are no-ops and listing fails. Requests already in flight at that point gain a record on their next log delivery.
3239

0 commit comments

Comments
 (0)