Skip to content

[vqueues] Fix a bug with a lost wakeup on inbox event - #5085

Merged
MohamedBassem merged 1 commit into
mainfrom
pr5085
Jul 28, 2026
Merged

[vqueues] Fix a bug with a lost wakeup on inbox event#5085
MohamedBassem merged 1 commit into
mainfrom
pr5085

Conversation

@MohamedBassem

@MohamedBassem MohamedBassem commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

The vqueues DRR scheduler wasn't waking up the waker whenever an inbox event happens (e.g. an entry is enqueued). It seems like it was there before, and got removed as part of this commit. This is currently not causing any issues because we're constructing a fresh scheduler stream on every LeaderState::run, so wakers are not that useful there. However, with the scheduler of the next PR, it relies on the wakers to figure out which streams to poll, and this bug clearly manifests there.
For simplicity, I'm callin the waker with every on_inbox_event call, though admittedly, some events won't result into different scheduler decisions. The original commit had a more invovled should_wake propagation, happy to copy it if deemed necessary.

Note: This is a bug that codex found as part of my testing

@github-actions

github-actions Bot commented Jul 21, 2026

Copy link
Copy Markdown

Test Results

  8 files  ±0    8 suites  ±0   5m 6s ⏱️ -1s
 61 tests ±0   61 ✅ ±0  0 💤 ±0  0 ❌ ±0 
268 runs  ±0  268 ✅ ±0  0 💤 ±0  0 ❌ ±0 

Results for commit e2ada40. ± Comparison against base commit e47043e.

♻️ This comment has been updated with latest results.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c86fd62be4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

///
/// Since v1.7.3
#[cfg_attr(feature = "schemars", schemars(skip))]
pub self_proposal_queue_memory_limit: NonZeroByteCount,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Add release notes for the new queue limit

This adds the user-facing worker.self-proposal-queue-memory-limit option and changes leader self-proposal buffering/backpressure behavior, but the commit does not add any release note under release-notes/. Without a release note, operators upgrading to this version won't see the new per-partition memory limit/default or know how to tune it.

AGENTS.md reference: AGENTS.md:L51-L51

Useful? React with 👍 / 👎.

MohamedBassem added a commit that referenced this pull request Jul 22, 2026
This PR replaces the current `stream_select` inside `LeaderState::run` with a byte aware DRR scheduler that ensures fairness across the different self proposer writers. A stream (e.g. schema upserts) dumping a 32MB command inside the self proposer, will get penalized for a bit allowing other streams to write to the self proposer.

The scheduler refills each stream with 64KB credits per round (an arbitrary number tbh), and fast forwards if all the streams are in deficit. A stream that still has credits will get polled multiple times until it either moves to Pending or exhusts all of its credits. Because we allow the streams to get polled first, then charge back their bytes, a stream can end up with a negative deficit. Streams with negative deficits won't get polled until they're in the positive again.

Implementation wise:
1. We're introducing a new scheduler that keeps track of the states of the different flows. This scheduler gets polled for the next flow to be polled, and its returns a decision. The decision struct should then reprot back the result of this poll (bytes written, pending, etc) for the scheduler own tracking.
2. We got rid of the large `LeaderEvents` enum as now no longer need to collect all stream outcomes into one container.
3. One improvement over the current design is that we no longer need to poll all the streams on every `LeaderState::run` call. But that also means that the correctness of wakers are more important as seen in #5085.

Perf wise, my local benchmarks report no regression in the simple 1000 connection, single VO gets benchmark:

```
wrk -t1 -c1000 --latency -d30s -s ./scripts/wrk/counter.lua http://localhost:8080                                                                                                                                                                                                                                   main ✱ ◼
thread 1784720132 started
Running 30s test @ http://localhost:8080
  1 threads and 1000 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    47.07ms   39.32ms   1.10s    99.48%
    Req/Sec    22.18k     2.73k   32.18k    72.58%
  Latency Distribution
     50%   44.00ms
     75%   51.03ms
     90%   58.43ms
     99%   75.60ms
  660389 requests in 30.05s, 175.71MB read
Requests/sec:  21979.32
Transfer/sec:      5.85MB
thread 1784720132 made 661389 requests and got 660389 responses
```

@tillrohrmann tillrohrmann left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think originally Ahmed had planned that the scheduler would/could run in its own task and therefore he kept the waker around to wake it up on certain events. With 4f22aa677816#diff-02cc9fd99c15c55730f0822a024e9d2c6bd7f4f92d3cc2d8c9d030773f1d6f6d, we settled on the scheduler being run as part of the partition processor loop. Therefore, if I recall correctly, we removed the waking logic.

If you need this bit for subsequent changes (like the leader event scheduler), then it probably makes sense to revisit this part so that we properly wake the scheduler up on all external signals that transition the scheduler into a state where it should be polled.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 010ec45d04

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

/// Default: 64 MiB
///
/// Since v1.7.3
#[cfg_attr(feature = "schemars", schemars(skip))]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Expose the queue limit in the config schema

This adds the documented worker.self-proposal-queue-memory-limit tuning knob, but schemars(skip) keeps it out of the generated configuration schema (cargo xtask generate-config-schema builds the schema from Configuration). Operators and tooling that rely on that schema for config validation or editor completion will not be able to discover or validate the new backpressure limit, unlike the other public byte-size worker options; unless this is intended to be private, remove the skip.

Useful? React with 👍 / 👎.

@AhmedSoliman AhmedSoliman left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm afraid we will need to have the more elaborate should_wake to reduce spurious wakes on the main pp task.

@MohamedBassem

Copy link
Copy Markdown
Contributor Author

@AhmedSoliman ok, I can port what was there in the old commit 👍

The vqueues DRR scheduler wasn't waking up the waker whenever an inbox event happens (e.g. an entry is enqueued). It seems like it was there before, and got removed as part of [this commit](4f22aa677816#diff-02cc9fd99c15c55730f0822a024e9d2c6bd7f4f92d3cc2d8c9d030773f1d6f6d). This is currently not causing any issues because we're constructing a fresh scheduler stream on every `LeaderState::run`, so wakers are not that useful there. However, with the scheduler of the next PR, it relies on the wakers to figure out which streams to poll, and this bug clearly manifests there.
For simplicity, I'm callin the waker with every `on_inbox_event` call, though admittedly, some events won't result into different scheduler decisions. The original commit had a more invovled `should_wake` propagation, happy to copy it if deemed necessary.

Note: This is a bug that codex found as part of my testing

@AhmedSoliman AhmedSoliman left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work. Thanks for fixing it properly ❤️

@MohamedBassem
MohamedBassem merged commit 4b353e6 into main Jul 28, 2026
57 checks passed
@MohamedBassem
MohamedBassem deleted the pr5085 branch July 28, 2026 16:37
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 28, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants