Repository navigation
Conversation
Every finished HTTP request spawned a task that waits for the actor's in-flight requests to reach zero before re-arming the sleep timer. Under steady concurrent load the count rarely reaches zero, so these tasks piled up, one per request, and every idle notification (from any counter wired to idle_notify) woke all of them to re-check and wait again. CPU per call grew with the backlog: 0.7 ms with one request in flight, 18 to 43 ms with 4 to 64, and worse the longer the load lasted. A request now spawns the waiter only if none is pending: an AtomicBool on SleepState is claimed before spawning and released when the waiter returns, just before it resets the sleep timer, so a request finishing in that gap is covered by the reset that follows. With the change, a call costs 0.7 ms of CPU at every concurrency (1 to 64 in flight, held for 60 s). Fixes rivet-dev#5991
Contributor
|
The changes look good; no high-confidence bugs or CLAUDE.md compliance issues found in the supplied commit range. GitHub authentication was unavailable, so PR status and existing Claude comments could not be verified. Copy prompt to fix all |
This branch has not been deployed
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.
Fixes #5991.
Every finished HTTP request to an actor spawned a task, through
wait_until, that waits for the in-flight request count to reach zero and then re-arms the sleep timer. Under steady concurrent load the count rarely reaches zero, so these tasks pile up, one per request. Every notification on the sharedidle_notifywakes all of them, and each takes theNotify's mutex, sees requests still in flight, and waits again. CPU per call grows with the backlog.This keeps one such task per actor. An
AtomicBoolonSleepStateis claimed before spawning and released when the waiter returns, just before it resets the sleep timer. A request that finishes in that gap is covered by the reset that follows. If the actor stops while a waiter is pending, the flag stays set, but the actor's next wake starts with fresh sleep state.Results
rivetkit-napibuilt from the v3.0.6 tag, without and with this change (both files are unchanged between v3.0.6 andmain). One actor whose action inserts a SQLite row, called from the same process; Bun 1.4.3, Linux x86-64, 22 cores:After the change it held for 60 s at each level: 0.7 ms of CPU per call and 0.3 cores, at 1, 16 and 64 in flight.
Before the change,
perf(on a build with symbols) put about three quarters of the CPU in the kernel's futex spin lock. The named frames above it wereMutex::lock_contendedintokio::sync::notify::NotifiedProject::poll_notified, underActorContext::wait_until(rearm_sleep_after_request).Testing
cargo fmt,cargo check -p rivetkit-core, and the reproduction below. I didn't add a test: I couldn't find tests forrivetkit-corein this repository, and the bug shows up only as CPU time. Happy to add one wherever you'd like it.Reproduction (repro.ts)
package.json:{ "type": "module", "dependencies": { "rivetkit": "3.0.6" } }, thenbun install && bun repro.ts 60 1,4,16,64.