Repository navigation
Propose that an idle queue is swept only at a real deadline, caught up on its next request, and parked after 24 h, and that each wake-up attempt is billed - #150
Open
sorenbs wants to merge 1 commit into
Conversation
…p on its next request, and parked after 24 h, and that each wake-up attempt is billed A queue with anything pending stays on its shard's roster and is swept at its next deadline, or an hour out when none applies. A forgotten queue with a backlog is swept about 96 times under the default retention. A drained one is swept for up to a day while its debt waits for the collector's daily pass. An unanswered wake-up subscription is notified once a minute until its backlog expires. On 2026-11-02 a queue cell served about 14 cold touches a second, so a million forgotten queues swept once an hour would need about as much capacity as a million in use. docs/QUEUES-IDLE.md is revision 9 of the queues design, proposed and not implemented: - sweeps only at real deadlines, with deletion debt in its own index; - a roster keyed by deadline; - one sweep step on an overdue queue's next request; - parking after 24 h without a request, swept at most once a day; - wake-ups dormant after 24 h without a useful claim; - each attempted wake-up notification billed as a queue operation. The doc also records four findings in the current code: - the sweeper reads only the first 4,096 roster rows of a shard, so queues past them are never swept; - the collector re-reads every roster queue's state row every 30 s; - notifications are sent one at a time on the sweeper's tick; - the per-project notification budget is not built. QUEUES-DESIGN.md §6.8, §8.1, §9.2, §10 and §14 point to it, and §14 adds decisions D23-D28. D14 counts wake-up attempts. OBSERVABILITY-BILLING.md §5 adds the wake-up row, and docs/README.md maps the new document. The owner approved the direction and decided the billing of wake-up attempts on 2026-11-03. Documentation only: no code, tests, ledgers or receipts change. Edge change: none now; dormancy, the wake-up billing, parkedAt and late retirement of a parked queue's data each become a record when they land. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sorenbs
added a commit
that referenced
this pull request
Nov 4, 2026
…ge after the last, so a shard with more rostered queues than one page holds sweeps every one of them Why: #150, finding 1 (the tuning plan's P3 addition). The sweeper read the roster's first page (4,096 rows in hash order) every tick and swept the due queues on it: a queue past the first page was never swept while the queues ahead of it stayed rostered, so its expired leases never came back, its retries never fell due by time alone, its failures never expired and its wake-ups never fired. At 100k queues on one shard (habanero's queue cell) that is 96% of them. Change: src/shard/queue_maintenance.rs: roster_page(after) reads at most ROSTER_PAGE rows after the queue `after` (from the start for None) and returns where the next page starts, None once a page reaches the roster's end; the sweeper loop keeps that cursor between ticks, so every rostered queue is examined within ceil(rows / ROSTER_PAGE) + 1 ticks. queue_roster (the collector's first page) reads it through roster_page(None), unchanged. roster_hash and roster_deadline name the row's parts. Red (the sweeper reading the first page every tick): shard::native_queue_tests::roster::the_sweeper_reaches_every_rostered_queue_past_its_first_page assertion `left == right` failed: 40 of the 40 due queues past the first page were never swept left: 40 right: 0 The test puts 4,096 roster rows of queues due in a thousand years ahead (in hash order) of 40 due queues, and asserts each due queue's roster row deleted and state row off the roster (roster_at None), and every undue row kept exactly. Green: that test, and every native queue and transaction test (82), on slate d16f1b0. Controls: none. Ledgers: test code only beside queue_maintenance.rs (its mutation owner exists); no owners.json row. Formal receipts: none staled. Edge change: none (a queue past the first page is now swept as one on it always was). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sorenbs
added a commit
that referenced
this pull request
Nov 4, 2026
…ir wake-ups 16 at once, so a shard's sweeps share commit groups instead of waiting one durable write each Why: #150, finding 3, and a throughput limit found on the way (the tuning plan's P3 addition). The sweeper awaited each sweep's durable reply before submitting the next: one sweep per commit window, about 10 a second at the production WAL window, below the 28 a second 100k queues need (each acked queue carries collection debt and comes back on the roster an hour later), and the cold warm-up could not group them because they never shared a group. Each wake-up notification was awaited the same way, so one receiver that took its whole timeout held back every other queue's notification. Change: src/shard/queue_maintenance.rs: sweep_due_queues submits the page's due queues SWEEPS_AT_ONCE (64, as many as a group warms at once) at a time (buffer_unordered), collects the wake-ups they ask for (wake_of; a refused sweep is retried at the queue's next roster turn, as before) and posts them NOTICES_AT_ONCE (16) at a time (for_each_concurrent). Each sweep is the same NqOp::Sweep as before. Red (SWEEPS_AT_ONCE 1, one sweep at a time): shard::native_queue_tests::roster::the_sweeper_sweeps_a_ticks_due_queues_together assertion `left == right` failed: the due queues' sweeps run together left: 1 right: 64 80 due queues, every state-row load held open (test_support hold_native_state_reads): the most loads in flight at once, then every queue swept (each roster row deleted). Green: both roster tests, and every native queue and transaction test (83), on slate d16f1b0. Controls: none. Ledgers: mutation-owner-sizes.json re-measured for this stack (nq_warm 23, queue_maintenance 158 from 125, nq_claim 67, nq_stage 124, and the drift slate's own commits left in eight other owners); no owners.json row (futures_util combinators, no spawn). Formal receipts: none staled. Edge change: none (sweeps and wake-ups as before, sooner). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Documentation only. This proposes how queues that nobody uses stop costing sweeps and wake-ups, and records the decision to bill each wake-up attempt. Nothing is implemented here.
Why
While a queue has anything pending, it stays on its shard's roster. It is swept at its next deadline, or an hour out when no deadline applies (
nq_roster_target). Nothing tells a queue in use from a forgotten one:On 2026-11-02, a queue cell with 25 ms store latency served about 14 cold touches a second. A million queues touched once an hour needed 32 cells. A million forgotten queues swept once an hour are the same rate of cold work, and they earn nothing.
What changes
New:
docs/QUEUES-IDLE.md, revision 9 of the queues design, with decisions D23-D28:Amended:
QUEUES-DESIGN.md: §6.8, §8.1, §9.2 and §10 point to the new doc. §14 adds D23-D28, and D14 counts wake-up attempts.OBSERVABILITY-BILLING.md§5: a row for wake-up attempts.docs/README.md: an entry for the new doc.Findings in the current code (not fixed here)
queue_rosterreads only the first 4,096 roster rows, ordered by hash, on every tick. A shard with more than 4,096 queues on its roster never sweeps, wakes or collects the debt of the rest.capture_debtreads the state row of every queue on the roster page every 30 s.sweep_due_queuesawaits each notification in turn, so a receiver that takes its full 2 s delays every queue after it.probe_debtcounts the roster's earliest deadline. The code doesn't yet, so a closed shard's queue timers wait until something else opens it.Decisions
The owner approved the direction on 2026-11-03: catch-up on access instead of hourly sweeps, parking after 24 h, and stopping wake-ups after 24 h. The owner also decided D28. The details of D23-D27 are for review.
Breaking changes
None now. Once implemented, wake-up dormancy, the billing of wake-up attempts,
parkedAt, and the late retirement of a parked queue's data are each client-visible. Each becomes an edge record when it lands.🤖 Generated with Claude Code