Shared caches hold completed values

A Worker isolate can serve several requests. A request owns its unfinished I/O. Shared caches must contain completed values.ΒΆ

The cold-isolate 1101 failure in PR #64 crossed that boundary. ContentStore held pending asset reads in a shared cache. Another request could await work owned by the first request.ΒΆ

Effect.cached, Effect.cachedWithTTL, and Effect.cachedInvalidateWithTTL can share pending work. A successful result cache and a pending-work cache have different lifetimes.ΒΆ

Store the result after the read

ContentStore keeps an Option in a Ref. Each request reads that completed-value cache first.ΒΆ

Concurrent misses can repeat a read. They do not wait for another request’s unfinished read.ΒΆ

request A ── cache miss ── asset read ── completed value ── cache
request B ── cache miss ── asset read ── completed value ── cache
request C ── cache hit  ──────────────────────────────── value

The cache is a derived copy of generated content assets. The content build writes those assets; requests store only successfully decoded values.ΒΆ

Check the lifetime at construction

rat-stack-patterns/no-shared-pending-cache rejects these cache constructors in module, service, and Worker initialization effects. Keep request-local work inside its request handler.ΒΆ

A targeted exception must explain the cached value and its lifetime with a -- reason. CryptoKey derivation from a fixed secret needs separate review from request-bound asset reads.ΒΆ

The fixture tests plant the old ContentStore.make cache shape. The rule rejects it before it can reach a Worker.ΒΆ

See Worker init runs twice8 for the initialization boundary and the fence39 for validation.ΒΆ

Sources

  1. Cache completed content without shared request I/O. GitHub joelhooks/rat-stack. ContentStore replaces shared pending asset reads with completed-value caches. Accessed 2026-10-08.
  2. Be explicit about lifetimes. GitHub just-be-dev. Assign each resource and mutable value to an explicit lifetime. Accessed 2026-10-08.
  3. Request lifetime guardrail. GitHub just-be-dev. Keep request identity and instance locks within their owning lifetimes. Accessed 2026-10-08.

Last changed 2026-10-08 in ad718e1. Source on GitHub. Change log.

Linked from

  1. Agent guide. An Effect stack so pure (aspirational) Kit Langton will blush.

    Shared caches hold completed values β€” Keep pending request I/O out of isolate-scoped caches.

  2. Change log. What changed in the files served here, newest first.

    Shared caches hold completed values β€” new page: feat: fence shared pending caches and teach request lifetimes

  3. Effect + Alchemy peer patterns. Source-grounded patterns from repos on nearby Effect and Alchemy pins.

    rat-stack already adapts this guidance in cache completed values, UI tests, and opt-in tracing.

  4. Full agent guide. An Effect stack so pure (aspirational) Kit Langton will blush.
  5. profile-a-worker. Capture a CPU or heap profile of a deployed Cloudflare Worker or Durable Object and read it with pprof. Use when a Worker is slow, burns CPU, nears its memory limit, throws Exceeded Memory, or you need to know which function costs the most in production.
    Link context

    Common wins: compute a value once instead of per call, cache a completed value, stop building objects you throw away, remove code that a flag only half disables.ΒΆ

  6. Rat Stack lore | rat-stack. Short, source-grounded notes on the ideas and decisions behind rat-stack.

    Shared caches hold completed values β€” Keep pending request I/O out of isolate-scoped caches.

  7. Source change history (log.md). The generated change log as Markdown.

    Shared caches hold completed values β€” new page: feat: fence shared pending caches and teach request lifetimes