Skip to content
sluice

Limitations

Stated in the open, because a reliability library that hides its own edges isn't one you should trust with a charge card.

ESM-only

@jamessuuu/sluice, @jamessuuu/sluice-store-postgres, and @jamessuuu/sluice-testkit ship ESM only, Node ≥ 22. No CommonJS build. If your project is still on require(), you need import() or a bundler that handles dual interop for you — sluice does not ship a CJS fallback.

TTL is a memory horizon, not a correctness knob

retentionMs (default 7 days) controls how long a terminal effect record stays around for replay/dedup purposes — not a promise about correctness. Set it longer than the longest duplicate-delivery window you can realistically see. After a record expires, the same idempotency key executes again from scratch. This is the one way sluice can be made to shoot you in the foot: a retention window shorter than your actual redelivery window silently reopens the exact hole sluice exists to close.

Hash-chain append throughput ceiling

sluice_event appends are serialized per namespace by a cursor row lock (the mechanism that makes the hash chain tamper-evident with a single SQL statement — see stores & migrations). Honest ceiling: roughly hundreds of events per second per namespace on Postgres. Fine for approval/audit-grade event volume; not a general-purpose event bus. If you need higher throughput than that, use more namespaces (each has an independent chain and cursor) rather than forcing everything through one.

Circuit breaker: eventually consistent across instances

Breaker state (sluice_circuit) is read-through cached 1 second in-process. Two instances of your service can disagree about whether a circuit is open for up to that long. Half-open's single-probe admission is still correctly serialized (compare-and-set on half_open_owner) even under this cache — the 1s window only affects how quickly an instance notices the circuit changed state, never whether two instances can both probe.

Clock-skew ceiling

With skew between worker clocks leaseMs / 2, there is no double execution — leases and gate timeouts are compared with a skew allowance. Beyond that ceiling sluice fails closed to indeterminate rather than risk a double execution (failure mode F8, asserted by the clock-skew chaos scenario at both "within" and "beyond" the ceiling on every seed). If your fleet's clocks can drift further than half a lease, raise leaseMs or fix your clock sync — don't rely on sluice to paper over it.

Chaos numbers are virtual-clock time, not wall-clock time

Every latency figure the chaos harness publishes (p50, p99 on the homepage) is measured on a VirtualClock — the harness auto-advances simulated time to the next due timer, so a scenario spanning hours of gate timeouts and lease expiries completes in milliseconds of real time. That's what makes pnpm chaos fast enough to run in CI on every push, but it means those numbers describe sluice's scheduling behaviour (how much simulated time elapses waiting on leases, backoff, and timeouts), not real network or database latency. Your production p99 will include actual I/O time on top.

Non-goals (repeated from the README, because it matters here too)

No domain logic (no email/Slack senders, no incident model, no scheduler, no notification delivery — approvers are opaque strings). No LLM anywhere in core. No policy DSL, PII scanning, or "risk scoring". Not a workflow engine — sluice runs inside one step of yours, it does not orchestrate the workflow around it. No telemetry, ever.