Crash Recovery Primitives
Invariant persists facts needed by a future recovery host, but the current public Beta does not provide a complete end-to-end recovery API.
Persist Stable Effect Intent
ts
import { invariant } from "@invariant-tech/sdk";
import { z } from "zod";
const payments = {
charge: async (request: { orderId: string; idempotencyKey: string }) => ({
chargeId: `charge_${request.idempotencyKey}`,
}),
};
const app = invariant();
export const workflow = app
.workflow("recoverable-order", {
inputSchema: z.object({
orderId: z.string(),
paymentRequestId: z.string().min(1),
}),
})
.capability("charge-order", {
idempotencyKey: "charge:{{runId}}",
handler: async ({ input }) => payments.charge({
orderId: input.orderId,
idempotencyKey: input.paymentRequestId,
}),
});Before the handler runs, a configured store commits the execution state, events, and Invariant command intent. If non-public, store-specific recovery code dispatches again, it must reuse the application-owned paymentRequestId; the payment provider must deduplicate that key. The public Beta does not expose the pending-command claim or execution-attach operations required to perform this loop portably.
Target Recovery Loop (Not Yet Public API)
A complete recovery host would need this sequence:
text
findRunnableExecutions()
│
▼
acquireLease(runId, workerId, ttlMs)
│
▼
loadState(runId) + readEventLog(runId)
│
▼
load pending commands from the store implementation
│
▼
dispatch with the original idempotency identity
│
▼
commit result event + command acknowledgement
│
▼
releaseLease(runId, leaseId)The common RuntimeStore contract stops before load/claim pending commands and attach execution. Do not present the sequence above as copyable Beta code or claim that applications can implement it portably today.
Future Recovery Acceptance Tests
These are acceptance criteria for a future public recovery host, not tests that the current release gate claims to satisfy end to end:
- Kill the worker after command intent is committed but before handler invocation.
- Kill it after the external provider succeeds but before completion is committed.
- Verify that another host cannot acquire an unexpired lease.
- Verify that an expired lease can be reclaimed.
- Verify that redispatch uses the same provider idempotency key.
- Verify that only one completion transition wins OCC.
Current Guarantee
With a durable configured store, Invariant guarantees that committed state, events, and command intent remain stored. It does not guarantee public SDK recovery or redispatch after a process restart. See the canonical Recovery Contract Matrix.