Skip to content

perf(courier): read and write attachments with the store free - #82

Merged
httpsphl merged 1 commit into
mainfrom
perf/files-outside-store
Oct 1, 2026
Merged

httpsphl merged 1 commit into
mainfrom
perf/files-outside-store

Conversation

@httpsphl

@httpsphl httpsphl commented Oct 1, 2026

Copy link
Copy Markdown
Owner

Second performance round, slice 3.

What

Two places held the single store mutex while doing file I/O:

  • Courier. The cycle locked the store once and kept it through every due delivery. That included render, which reads each image the message inlines (up to 5 MB), base64-encodes it, and builds the stream-json line.
  • messages.send. It decoded the owner's base64 uploads and wrote them to the bot's attachments\ folder while holding the store.

Meanwhile every chat item from a working bot, every MCP tool call and every app request waited for the lock. As #81 showed, a tokio worker blocked on that mutex also stalls the runtime's timers.

Now:

  • The courier locks per step.
    • Recovering leases, expiring tasks and reading the queue take one short lock.
    • Each delivery is prepared under its own lock. prepare now returns a Draft with the data it read, instead of the rendered line.
    • The draft is rendered, images included, with the store free.
    • Claiming, writing and finishing take one more lock. claim_delivery still refuses a delivery that something else changed meanwhile.
  • messages.send checks the bot, saves the files with the store free, then checks the bot again before storing the message. A bot archived or deleted in that gap gives the same error as before; the saved files stay in its folder.

No behavior changes, and the spec stays true. The full suite, clippy and fmt pass; the existing courier, attachment and inline-image tests cover these paths.

Manual check (real Claude)

Send a bot a message with two large photos (3–5 MB each) while another bot in the crew is streaming a long answer. The answer keeps streaming, and the photo reaches the bot as before (it describes the image).

The courier held the store for its whole cycle, including reading each
inline image (up to 5 MB) and base64-encoding it, and messages.send
decoded and wrote the owner's files (up to the attachment limit) under
the store lock. Every chat item, tool call and request waited. The
courier now locks per step and renders a delivery between them; claiming
still checks the delivery is waiting. messages.send saves the files
first and checks the bot again before storing the message.
@httpsphl
httpsphl merged commit 419536b into main Oct 1, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant