Skip to content

feat(examples): keep alchemy-cloudflare Durable Objects running on pending I/O - #53

Merged
K-Mistele merged 1 commit into
effect-v4-stablefrom
do-pending-io-keepalive
Oct 4, 2026
Merged

K-Mistele merged 1 commit into
effect-v4-stablefrom
do-pending-io-keepalive

Conversation

@K-Mistele

Copy link
Copy Markdown
Contributor

Stacked on #52 (Effect 4.0.0 / Alchemy beta.80).

Cloudflare's pending I/O keep-alive change: from compatibility date 2026-10-01, pending calls to another Durable Object, service bindings, container.monitor(), waitUntil and timers keep a Durable Object in memory with no client connected. Each call is covered for up to 15 minutes. Outbound fetch() already was.

Changes

  • Worker.ts and computer/ComputerWorker.ts move from compatibility date 2026-08-31 to 2026-10-01. The only other change in that range is Python 3.14 for Python Workers.
  • Keepalive stays, with corrected comments. Pending I/O keeps a running turn in memory, but a deploy or crash still ends it. Keepalive's alarm is what wakes a cut-off session so it continues the turn. Its comment also claimed model fetches didn't count as activity, which was wrong: the real gap was the RPC call to the Computer.

Deploy-only for now

Alchemy beta.80 passes the date straight through, so deploys work. Local alchemy dev runs workerd 1.20260918.1, which probably refuses a later compatibility date until Alchemy pins a newer workerd.

Watch out: Alchemy beta.80's default stage changed

The default stage changed from dev_${USER} to live_${USER}. A plain alchemy deploy on beta.80 therefore planned a whole new stack. It created a second ChatWorker, re-uploaded the fixed-name Computer Worker, and failed on the container app. I cleaned up as follows:

  • removed the live stage's record of the shared Computer Worker, without deleting the Worker;
  • destroyed the live stage, which deleted its ChatWorker and its stray container app;
  • redeployed with --stage dev_kylemistele.

Existing deployments need --stage dev_<user> or ALCHEMY_STAGE from now on.

Tested on Cloudflare

I deployed the dev_kylemistele stage and sent a message whose bash container command was sleep 240; echo finished-sleep. The HTTP client disconnected after 20 seconds. The command returned finished-sleep about four minutes later and the turn completed, with no restart nudge in the log. Caveat: I polled the log every 30 seconds and Keepalive's alarm still runs, so this shows the turn survives a disconnected client, not the new rule on its own.

Typecheck, lint, format and the example's 25 tests pass.

🤖 Generated with Claude Code

…nding I/O

Move both Workers to compatibility date 2026-10-01. From that date, a
pending call to another Durable Object, a container, `waitUntil` or a
timer keeps a Durable Object in memory with no client connected, for up
to 15 minutes per call. A turn waiting on a container command through the
Computer is now covered without its HTTP client.

Keepalive stays: pending I/O does not survive a deploy or crash, and its
alarm is what wakes a cut-off session so it continues the turn. Its
comments now say so, and drop the claim that outbound fetches did not
count as activity.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
HumanLayer-Session: https://app.dev.codelayer.gg/sessions/01a0f3fc-13b0-758f-a343-fae04e83a7a9
@K-Mistele
K-Mistele merged commit 2c2d9d1 into effect-v4-stable Oct 4, 2026
4 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