# Shared caches hold completed values

> For agents: start with the [agent guide](https://ratstack.sh/llms.txt). Every page is Markdown by default; add `Accept: text/html` for HTML.

Free workshop: [how to burn a trillion tokens and get good results](/tokenmaxx#interested).

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](https://github.com/joelhooks/rat-stack/pull/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.

- A hit returns the completed value.
- A miss reads assets within the current request.
- A successful read stores its completed value.
- A failed read leaves the cache empty.

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

```text
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 twice](/lore/init-runs-twice) for the initialization boundary and [the fence](/lore/the-fence) for validation.

## Sources

1. [Cache completed content without shared request I/O](https://github.com/joelhooks/rat-stack/commit/18d4921)
   GitHub joelhooks/rat-stack. ContentStore replaces shared pending asset reads with completed-value caches. Accessed 2026-10-08.

2. [Be explicit about lifetimes](https://github.com/just-be-dev/effect-cloudflare-foldkit-template/blob/04851db8649501bfaf8d2712429074ba0290a10f/docs/architecture.md)
   GitHub just-be-dev. Assign each resource and mutable value to an explicit lifetime. Accessed 2026-10-08.

3. [Request lifetime guardrail](https://github.com/just-be-dev/effect-cloudflare-foldkit-template/blob/04851db8649501bfaf8d2712429074ba0290a10f/docs/guardrails.md)
   GitHub just-be-dev. Keep request identity and instance locks within their owning lifetimes. Accessed 2026-10-08.

## Linked from

- Agent guide → An Effect stack so pure (aspirational) Kit Langton will blush. → [Read page](https://ratstack.sh/llms.txt)

- Change log → What changed in the files served here, newest first. → [Read page](https://ratstack.sh/log)

- Full agent guide → An Effect stack so pure (aspirational) Kit Langton will blush. → [Read page](https://ratstack.sh/llms-full.txt)

- Rat Stack lore | rat-stack → Short, source-grounded notes on the ideas and decisions behind rat-stack. → [Read page](https://ratstack.sh/lore)

- Source change history (log.md) → The generated change log as Markdown. → [Read page](https://ratstack.sh/log.md)
