once について
onceは、リトライ、重複配信、並行ワーカーによる副作用の再実行を防ぐPython向け冪等性ライブラリです。ペイロード検証とリースに加え、インメモリ、SQLite、PostgreSQLのストアを利用できます。
主な機能
- 01単一実行者の原子的な選出
- 02ペイロードの指紋化と競合検出
- 03フェンストークンによるリース回復
- 04同期・非同期API
- 05インメモリ、SQLite、PostgreSQLのストア
活用シーン
- 01リトライによる決済の重複実行防止
- 02Webhookやキュー配信の重複排除
- 03複数ワーカープロセス間で冪等性状態を共有
- 04イベントループを塞がずに副作用を非同期実行
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
once
1,000 人の呼び出し元がまったく同時に要求しても、副作用を正確に 1 回だけ実行します。

⚡ 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
これはモックではありません。今すぐ実行できるライブ攻撃です。
pip install once-kernel
python -m once.demo
問題
ネットワークは再試行します。ユーザーはダブルクリックします。キューはメッセージを再配信します。AI エージェントはツールを機械の速度で再実行します。 こうしたことが起きると、1 回の支払いが 2 回に、1 通のメールが 3 通に、1 台のサーバーが 200 台になりかねません。
多くのチームは冪等性テーブルを独自に実装します。しかし、その多くは同時負荷のもとでひそかに壊れています。同一の 2 つのリクエストが、どちらも「すでに完了しているか?」という確認を通過し、そのまま両方とも実行されるのです。バグは見つけにくく、損失は金銭に及びます。
once は、誰もが正しく使えるように作られた冪等性テーブルです。独自実装で見落とされがちな 4 つの防御機能を備えた、小さな 冪等性カーネル です。
- アトミックなリーダー選出 — 同時に発生した重複リクエストがすべてチェックを通過することはありません。実行するのは必ず 1 つだけで、残りはその結果を共有します。
- ペイロードのフィンガープリント(RFC 8785) — 同じキーで 異なる 本文が送られた場合は、必ず
IdempotencyConflictが発生します。他のリクエストのキャッシュ済み回答を返すことはありません。 - フェンストークン + 世代番号 — クラッシュしたワーカーのリースを引き継げます。また、「停止した」ワーカーが遅れて復帰しても、レコードを破損させることは できません。
- 正直な失敗状態 — 失敗した試行ではキーが再試行可能な状態に戻ります。不明な結果が、黙って再実行されることはありません。
使い方
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)
1 台のマシンで複数プロセスを実行する場合は、データベースサーバー不要です。SQLite だけで、インストールも不要です。
from once import Once
from once.sqlite import SqliteStore
o = Once(SqliteStore("/var/lib/myapp/once.db")) # schema auto-created
再起動後も状態が保持され、プロセス間で動作します(WAL モード)。デフォルトの MemoryStore はどちらにも対応しません。プロセスごとに独立しているため、2 つ目のワーカーを起動した時点で、それぞれが実行済みの処理について独自の認識を持ち、ガードはひそかに機能しなくなります。
複数のマシンで使う場合は、すでに運用している Postgres を通じて状態を共有できます。
from once import Once
from once.pg import PostgresStore
o = Once(PostgresStore("postgresql://user:pass@host/db")) # table auto-created
非同期(FastAPI、エージェント)の場合、同期的な副作用はワーカースレッドで実行され、待機側はイベントループ上で待機します(重複リクエストが集中してもスレッドプールが枯渇しません。これを証明するテストもあります)。
from once import AsyncOnce
ao = AsyncOnce()
result = await ao.run("pay:ord_1", payload, charge)
信頼できる動作
| こうなった場合 | こうなります |
|---|---|
| 同じキー + 同じペイロードが再度送られた | 保存済みの結果が返ります — 2 回目の実行はありません |
| 同じキー + 異なる ペイロード | IdempotencyConflict が発生します — 誤った回答が黙って返されることはありません |
| 最初のリクエストが 1,000 件同時に届いた | 実行するのは 1 つ だけです。他はすべて結果を共有する(wait=True)か、待つように通知されます |
| 実行中のワーカーが停止した | リースの期限切れ → 別の呼び出し元が引き継ぎます |
| 「停止した」ワーカーが遅れて復帰した | フェンスによってブロック されます — 完了も失敗もできず、レコードを破損させることもありません |
| 長時間のジョブがリース期間を超えた | heartbeat() によって保護が維持されます |
| 関数が例外を発生させた | キーが解放されます — 後続の再試行で実行できる場合があります |
正直なモデル(ポスターに載せてください):実行は正確に 1 回 + 結果の配信は少なくとも 1 回。 ネットワーク上で真の「正確に 1 回」を実現することは物理的に不可能です。それを謳うライブラリは嘘をついています。実行は 1 回だけ行い、求められた回数だけ結果を再 配信 します。
金銭が懸かっているかのようにテスト
実際に金銭が懸かっているからです。上記のすべての主張はカオススイートによって検証されます。バリアで強制するスレッドストーム、期限切れリースの再取得競合、ゾンビ書き込みのフェンシング、凍結時計によるタイムアウト攻撃、イベントループの枯渇検出などを、すべてのコミットでインメモリストアと実際の PostgreSQL の両方に対して実行します(Postgres のベンチマークがスキップされると CI は明確に失敗します)。CI で何も出力されなくても、「テストされていない」という意味ではありません。
また、自社の本番メール配信システムでも運用しています。同じ送信が二度承認された場合、実際の見込み顧客にメールを二重送信するのではなく、既存の結果を再配信します。まずは自分たちで使います。
対象外
- 決済プロバイダーではありません。お客様の決済プロバイダーへの呼び出しを保護します
- ワークフローエンジンではありません(サーガや複数キーのトランザクションはありません — 設計上の決定)
- 「あらゆる場所で厳密に一度だけ」を実現する魔法ではありません — 上記の正直なモデルをご覧ください
ドキュメント
- 使用例:FastAPI Webhook · Celery タスク — そして、実際に判断が必要な3つの決定(キー、ペイロード、ストア)
- 5分でできる導入ガイド
- API リファレンス全文
- ステートマシン — 許可される遷移と許可されない遷移
- 保存するデータ:結果サイズと PII ポリシー
- アーキテクチャ上の決定
関連プロジェクト — EffectFence(Rust)
EffectFence(cargo add effectfence)は、同じアイデアを Rust で実現したものです。ツールの副作用に対する因果フェンスであり、コンテンツアドレス方式の証明書と MCP プロキシモードを備えています — effectfence wrap -- <any mcp server> を使うと、コードを変更せずに別のサーバーのツール呼び出しをフェンスで保護できます(once-mcp で実証済み)。
副作用を伴う処理が Python で、永続的なストアが必要な場合は once を、フェンスが Rust 内にある場合や MCP サーバーの前段に置く場合は EffectFence をお使いください。
商用サポート
無料で Apache-2.0 ライセンスのまま、今後もその方針を維持します。すでに資金を動かしているコードベースへの適用支援をご希望の場合は、副作用を伴う経路の洗い出し、負荷試験、フェンスによる保護、そして保護状態を維持する CI テストまで対応します。[email protected] までメールでお問い合わせください。詳細: フェンス監査。
ライセンス
Apache-2.0
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。