Durability
What it does
Durability14 here means four things:¶
- A slow provider never holds a database connection.¶
- A request never waits on a provider after its data commits.¶
- A tunable changes without a code edit.¶
- A gate stops only real harm.¶
rat-stack uses Effect29’s own primitives for each one, in real seams. Agents load the durability skill before they change one of these seams.¶
Each card below has five fields:¶
- Problem: what goes wrong.¶
- Primitive: the Effect answer.¶
- Seam: where rat-stack uses it.¶
- Fence45: the test or lint rule that fails on the bug.¶
- Incident: where the lesson came from.¶
The incidents come from drovr on 2026-10-23.¶
1. Lease a connection for the query
- Problem: a connection held across a provider call starves the pool.¶
- Primitive:
RcRefwithidleTimeToLive, borrowed insideEffect.scoped.¶ - Seam:
packages/database/src/connection-lease.ts, used by the Hyperdrive Postgres run log8. Each request gets its ownRcRef, because workerd pins sockets to a request.¶ - Fence:
packages/database/test/connection-lease.test.ts, a model over queries, bursts, and provider waits.¶ - Incident: drovr car #2350.
mysql.acquirep95 rose from 0.06 s to 2.3 s while PostShiba was slow.¶ - Principle: lease-connections-per-query.¶
2. Answer at commit; dispatch off the request
- Problem: a request kept open across a provider call times out its caller.¶
- Primitive:
waitUntilat the edge, with a backstop that replays the same idempotency9 key.¶ - Seam:
joinIntakeLayercommits the contact asreadywith a pending-delivery marker, then answers.JoinRequest.afterResponseruns delivery throughwaitUntil. A five-minute intake sweep redrives every marked contact with its submission id.¶ - Erase: the same shape. The erase marks the contact, writes the event tombstone with bounded backoff, and removes the contact after the tombstone lands. The sweep finishes an erase that a Basin outage stopped.¶
- Fence:
packages/core/test/join-answer-at-commit.model.test.tsandpackages/core/test/intake-sweep.model.test.ts.¶ - Incident: drovr’s ingress forward. Five
POST /eventsanswered 503 after their events committed.¶ - Principle: answer-at-commit.¶
3. Set a provider timeout once
- Problem: timeout20 literals in several layers drift apart.¶
- Primitive: a
Context.Referencewith a default, read at layer18 build, thenEffect.timeoutOption.¶ - Seam:
DrovrIntakeTimeout. Browser and agent intake both read it. The Worker sets it fromDROVR_INTAKE_TIMEOUT_SECONDS.JoinDeliveryDeadlinegives every delivery one 25-second budget across its retries, under the 30-secondwaitUntilallowance.¶ - Fence:
packages/subscriber-delivery/test/intake-timeout.test.ts.¶ - Incident: drovr #2339 changed a PostShiba timeout by deploy.¶
- Principle: one-timeout-at-the-boundary.¶
4. Bound work in flight
- Problem: a serial loop lets provider latency set throughput. An unbounded fan-out floods the provider.¶
- Primitive:
Effect.forEachwithconcurrency, or aSemaphore.¶ - Seam: the application listing in
apps/site/src/interest/applications.tsreads 8 at a time, in id order.intakeRedeliverstops at the first outcome other than accepted and returns the rest.¶ - Fence:
apps/site/test/intake-applications-concurrency.test.ts.¶ - Principle: bound-in-flight-work-with-keys.¶
5. Scope waiters to the request
- Problem: a module-level
DeferredorSemaphorein a Worker isolate makes one caller wait on another caller’s work.¶ - Primitive: a
Deferred,Cache,Ref,Semaphore,Queue,Latch,PubSub,PartitionedSemaphore, orTxSemaphorecreated inside one request or runtime scope34.¶ - Fence:
rat-stack-patterns/shared-waiters, with a rejecting and an allowed fixture per constructor inpackages/core/test/patterns-rule.test.ts.¶ - Incident: drovr cars #2344 and #2348.¶
- Principle: scope-waiters-to-the-request.¶
6. Climb a flag with a ledger
- Problem: changing one value by deploy costs a plan, a readback, and another deploy to undo it.¶
- Primitive: a
Context.Serviceflags port27 withLayeradapters and a declared lifecycle machine26.¶ - Seam: the flags9 cartridge38. The lifecycle
declared → rollingOut → on → removedis the ladder.setFlagwrites a Pending key and a completion key for each attempt.¶ - Fence:
packages/flags/test/writes.model.test.tsandpackages/flags/test/lifecycle.model.test.ts.¶ - Incident: drovr shipped
postshiba-send-holddark behind three rungs.¶ - Principle: climb-flags-with-a-ledger.¶
7. Fail open on liveness, closed on harm
- Problem: a gate that refuses on delay stops good work. A fallback in front of real harm lets the harm through.¶
- Primitive:
Schema.TaggedErrorrefusals,Effect.catchTag, and bounded retries.¶ - Seam: the deploy driver refuses an unapproved replacement or deletion with
PlanRejected. It retries content-version mismatches until a deadline. A failed Worker flag read uses the Config value.¶ - Fence:
packages/deploy/test/plan.test.tsandpackages/deploy/test/content-propagation.model.test.ts.¶ - Incident: PostShiba’s p50 rose from 0.3 s to 8 s. 46 of 47 timed-out first asks still arrived, and drovr did not resend.¶
- Principle: fail-open-on-liveness.¶
The standard
- Every pattern has a seam in shipped code. Toy examples do not count.¶
- Every pattern has a fence. The fence fails on a planted copy of its incident’s bug.¶
- A provider call never runs inside a held database lease.¶
- The join answer never waits on drovr. The contact is
readybefore the answer leaves.¶ - Each provider has one timeout value. Config sets it at the composition root17.¶
- Every fan-out names its bound.¶
- Effect stays at the pinned version. These patterns add no dependency.¶
The idle lease of 250 ms is a guess. drovr lists the same value with an expiry. Measure it before you depend on it.¶
How to check
- Run
pnpm --filter @rat-stack/database exec vitest run test/connection-lease.test.ts.¶ - Run
pnpm --filter @rat-stack/core exec vitest run test/join-answer-at-commit.model.test.ts.¶ - Run
pnpm --filter @rat-stack/subscriber-delivery exec vitest run test/intake-timeout.test.ts.¶ - Run
pnpm --filter @rat-stack/site exec vitest run test/intake-applications-concurrency.test.ts.¶ - Plant a bug and watch its fence fail:
- Hold the lease for the whole request.¶
- Run delivery before the answer.¶
- Put
"20 seconds"back in the agent intake.¶ - Make the application read unbounded.¶
- Run
pnpm turbo run check test build --concurrency=1for the full gate.¶
Sources
- Durability skill. rat-stack. The skill hub and one principle file for each pattern on this page. Accessed 2026-10-23.
- Connection lease. rat-stack. Per-execution RcRef lease for the Hyperdrive Postgres executor. Accessed 2026-10-23.
- Join intake. rat-stack. Commits the contact, answers, and dispatches delivery after the response. Accessed 2026-10-23.
- Drovr intake adapter. rat-stack. DrovrIntakeTimeout, the one timeout both intake paths read. Accessed 2026-10-23.
- Workers context: waitUntil. Cloudflare. Work after the response keeps the Worker alive until it settles. Accessed 2026-10-23.
Last changed 2026-10-23 in 9b233db. Source on GitHub. Change log.
Linked from
- Agent guide. An Effect stack so pure (aspirational) Kit Langton will blush.
Durability — Seven durable Effect patterns, each with its seam, its fence, and the incident that taught it.
- Change log. What changed in the files served here, newest first.
Durability — edited: docs(durability): merge Switchboard’s research into the skill
- Database. One interface records action runs and their outcomes in either Cloudflare D1 or Postgres through Hyperdrive.
See Durability.¶
- durability. Keep a rat-stack app standing when a provider, pool, or dependency slows down or a worker dies. Use at any I/O boundary, connection pool, provider call, shared waiter, fan-out, flag, gate, or work that can outlive a request, or when asked "what happens when this is slow", "add a timeout", "make this durable", or "what survives a crash".
The public page is /systems/durability.¶
- Durability starts with a recovery record. A reading order for storage, replay, worker ownership, overload, and recovery tests.
The durability system page shows the patterns rat-stack ships.
- Full agent guide. An Effect stack so pure (aspirational) Kit Langton will blush.
- Interest signup. Agent-only applications start email confirmation through interfaces owned by core and delivery implemented in a separate package.
See Durability.¶
- Rat Stack systems | rat-stack. The systems rat-stack ships, the standard each keeps, and how to check it.
Durability — Seven durable Effect patterns, each with its seam, its fence, and the incident that taught it.
- Source change history (log.md). The generated change log as Markdown.
Durability — edited: docs(durability): merge Switchboard’s research into the skill