Quickstart
sluice wraps a side-effecting call in run(). Same idempotency key in, same
recorded outcome out — no matter how many times the call arrives.
import { createSluice, idempotencyKey, MemoryStore } from "@jamessuuu/sluice";
const sluice = createSluice({ store: new MemoryStore() });
async function chargeCard(customerId: string, amountCents: number) {
const outcome = await sluice.run(
{
// Derive the key from INTENT, never from the transport attempt.
// See "Idempotency keys" for why this is the whole ballgame.
key: idempotencyKey({ tool: "charge_card", customerId, amountCents }),
fingerprint: { customerId, amountCents },
leaseMs: 30_000,
deadlineMs: 60_000,
},
async (ctx) => {
const charge = await stripe.charges.create(
{ customer: customerId, amount: amountCents },
{ idempotencyKey: ctx.effectId } // belt + suspenders at the transport, too
);
return { chargeId: charge.id };
}
);
if (outcome.status === "executed") {
// fn ran; this call did the charging.
} else {
// outcome.status === "replayed" — someone already did this. `outcome.value`
// is the recorded result (unless resultOmitted — see the F10 row in
// "Failure modes").
}
return outcome;
}
Call chargeCard again with the same customerId/amountCents — from a retry, a
duplicate webhook delivery, a redelivered queue message — and the card is charged
once. The second call gets { status: "replayed", value: { chargeId: "..." } }
without re-running the effect function at all.
What just happened
run()atomically claims(namespace, key)in the store. Exactly one caller wins the claim; concurrent duplicates wait for the winner's outcome and replay it.- The effect function runs under a lease (default 30s, heartbeat at
leaseMs / 3) and a whole-run deadline (default 60s, retries included). - The result is persisted and the outcome returned. A caller that throws gets
classified
retryable/failed/indeterminate(see Failure modes) and retried, failed, or parked accordingly.
Next
- Idempotency keys — the one rule that makes any of this work.
- Retries & breaker — what happens inside one lease when the downstream is unreliable.
- Gates — durable human approval for the calls you don't want to auto-retry at all.
- Try it live:
/playgroundruns this exact core in your browser with duplicate/timeout/error sliders, and/gateis a 60-second walkthrough of a gate surviving a real page reload.