Repository navigation
Keep the app data supervisor's alarm armed across writes - #50
Merged
Merged
Conversation
Each app write set and deleted the supervisor's alarm and wrote a pending mark before the write, so one write cost five disk syncs: two alarm changes, two supervisor commits and the facet's own commit. On self-host every sync blocks the app process's only thread, so a slow disk capped all app writes. A write now arms the alarm only when this instance has none due, and does not write the pending mark or delete the alarm. An alarm this instance did not arm was left by one that stopped, possibly during a write, so it announces a new revision, as an earlier release's pending mark still does. Writes cost two syncs.
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.
Round 16, item 2: why 10 writes/s from one app saturates self-host while every process sits at low CPU.
Finding
The queue isn't in the product Durable Object. A tool call writes nothing to the product's storage, so
storage.sync()there takes about 0.02 ms, and the PGlite and connection locks wait under 0.1 ms.The queue is in the apps process. Every app write went through the app's data supervisor (
packages/app-data/src/cloudflare.ts), which did five disk syncs per write:pendingmark;On self-host each sync runs on that process's only thread, so while one is in progress every app in the process stops. That matches production: about 7.7 writes/s, low CPU on every process, and latency that grows with concurrency.
Change
pendingmark or deletes the alarm. The alarm stays armed while writes run and re-arms when it fires mid-write.pendingmark left by an earlier release is still honoured.Measured locally
Native self-host in Docker with 2 CPUs. An
LD_PRELOADshim added a fixed delay to eachfsyncto stand in for a slower disk. The figures are REST writes:Recovery
No scenario kills the process in the middle of a write, so this path is checked by reasoning only.
Tests
Self-host scenarios pass:
bun run checkpasses.