once
Run a side effect exactly once under retries, redelivery, and concurrent workers.
Open source Open in the app JSON README (API)
About
Run a side effect exactly once under retries, redelivery, and concurrent workers.
Details
- Kind
- MCP servers
- Topic
- No topic detected
- Publisher
- aurumflux20
- Origin
- official
- Category
- ferramentas
- Transport
- local
- Version
- 0.2.1
- Last push
- 2026-08-12T03:09:16Z
- Repository state
- ativo
- Language
- Python
- License
- Apache-2.0
- Added
- 2026-08-29 03:02:28
- Updated
- 2026-08-29 03:02:28
- Origin id
io.github.aurumflux20/once-kernel
README
# once
<!-- mcp-name: io.github.aurumflux20/once-kernel -->
**Run any side effect exactly once — even when 1,000 callers demand it at the same instant.**

```
⚡ once — STORM DEMO
1,000 concurrent attempts to charge order #777 ($49.00)
ACTUAL EXECUTIONS : 1 ← the whole point
served same answer : 1,000 / 1,000
elapsed : 0.1s
💰 double-spend prevented this run: $48,951.00
```
That's not a mock — it's a live attack you can run right now:
```bash
pip install once-kernel
python -m once.demo
```
## The problem
Networks retry. Users double-click. Queues redeliver. **AI agents re-fire tools at machine speed.** Any of these turns one payment into two, one email into three, one server into two hundred.
Most teams hand-roll an idempotency table — and most of those are [quietly broken under concurrent load](https://dev.to/chaitanya_srivastav_9bd5a/why-your-idempotency-implementation-is-probably-broken-under-concurrent-load-5b22): two identical requests both pass the "already done?" check, then both execute. The bugs are subtle, the failures are money.
`once` is that table done right, once, for everyone — a tiny **idempotency kernel** with the four defenses hand-rolled versions miss:
1. **Atomic leader election** — concurrent duplicates can't all pass the check; exactly one executes, the rest coalesce onto its result.
2. **Payload fingerprinting (RFC 8785)** — same key with a *different* body is a hard `IdempotencyConflict`, never someone else's cached answer.
3. **Fence tokens + generations** — a crashed worker's lease can be taken over, and when the "dead" worker wakes up late, it is *locked out* of corrupting the record.
4. **Honest failure states** — a failed attempt frees the key for retry; an unknown outcome never silently re-runs.
## Use it
```python
from once import Once
o = Once()
def charge():
return gateway.charge(order_id="ord_1", amount_cents=4900)
# Retries, double submits, webhook redelivery, agent fan-out → runs ONCE
result = o.run("pay:ord_1", {"order": "ord_1", "amount_cents": 4900}, charge)
```
One box, several processes, no database server — SQLite, nothing to install:
```python
from once import Once
from once.sqlite import SqliteStore
o = Once(SqliteStore("/var/lib/myapp/once.db")) # schema auto-created
```
Survives restarts and works across processes (WAL mode). The default `MemoryStore` does neither — it is per-process, so the moment you run a second worker each one keeps its own private idea of what already ran, and the guard silently stops guarding.
Several machines — share state through the Postgres you already run:
```python
from once import Once
from once.pg import PostgresStore
o = Once(PostgresStore("postgresql://user:pass@host/db")) # table auto-created
```
Async (FastAPI, agents) — sync side effects go to a worker thread, waiters park on the event loop (no thread-pool starvation under duplicate storms; there's a test that proves it):
```python
from once import AsyncOnce
ao = AsyncOnce()
result = await ao.run("pay:ord_1", payload, charge)
```
**[→ The full 5-minute guide](https://github.com/aurumflux20/once-kernel/blob/main/docs/FIVE_MINUTE_GUIDE.md)**
## What you can rely on
| If this happens | You get |
|---|---|
| Same key + same payload, again | The stored result — **no second execution** |
| Same key + **different** payload | `IdempotencyConflict` — never a silent wrong answer |
| 1,000 concurrent first requests | **One** executor; everyone else coalesces (`wait=True`) or is told to wait |
| Executing worker dies | Lease expires → another caller takes over |
| "Dead" worker wakes up late | **Fenced out** — cannot complete, cannot fail, cannot corrupt |
| Long job outliving its lease | `heartbeat()` keeps it protected |
| Your function raises | Key freed — a later retry may execute |
**The honest model** (put this on a poster): **exactly-once execution + at-least-once result delivery.** True network exactly-once is physically impossible — libraries claiming it are lying to you. We execute once and re-*deliver* the answer as many times as asked.
## Tested like money depends on it
Because it does. Every claim above is enforced by the chaos suite — barrier-forced thread storms, dead-lease reclaim stampedes, zombie-writer fencing, frozen-clock timeout attacks, event-loop-starvation detection — **run against both the in-memory store and real PostgreSQL on every commit** (CI fails loudly if the Postgres bench is skipped). Silence in CI never means "untested."
And we run it on our own production mailer — a double-approved send replays instead of double-emailing a real prospect. Dogfood first.
## Not this
- Not a payment provider — it guards *your* calls to one
- Not a workflow engine (no sagas, no multi-key transactions — [by decision](https://github.com/aurumflux20/once-kernel/blob/main/LOCKED.md))
- Not magic "exactly-once everywhere" — see the honest model above
## Docs
- [Examples: FastAPI webhook · Celery task](https://github.com/aurumflux20/once-kernel/tree/main/examples/) — and the three decisions that actually take judgement (key, payload, store)
- [5-minute integration guide](https://github.com/aurumflux20/once-kernel/blob/main/docs/FIVE_MINUTE_GUIDE.md)
- [Full API reference](https://github.com/aurumflux20/once-kernel/blob/main/docs/API.md)
- [State machine — legal & illegal transitions](https://github.com/aurumflux20/once-kernel/blob/main/docs/STATE_MACHINE.md)
- [What we store: result size + PII policy](https://github.com/aurumflux20/once-kernel/blob/main/docs/PII_AND_RESULT_POLICY.md)
- [Architecture decisions](https://github.com/aurumflux20/once-kernel/blob/main/LOCKED.md)
## Sibling project — EffectFence (Rust)
[**EffectFence**](https://github.com/aurumflux20/effectfence) (`cargo add effectfence`) is the Rust half of the same idea: a causal fence for tool side effects, with content-addressed certificates and an MCP proxy mode — `effectfence wrap -- <any mcp server>` fences another server's tool calls with zero code change (proven against `once-mcp`).
Use `once` when the side effect is Python and you want a durable store; use EffectFence when the fence lives in Rust or in front of an MCP server.
## Commercial support
Free and Apache-2.0, and staying that way. If you want help applying it to a
codebase that already moves money — side-effecting paths inventoried,
storm-tested, fenced, with a CI test that keeps them fenced — email
**hello@aurumflux.co**. Details:
[the Fence Audit](https://github.com/aurumflux20/effectfence/blob/main/SUPPORT.md).
## License
Apache-2.0