A:同じ処理を2回呼ぶと、加算も繰り返す?
この実装では、同じ入力でも加算が重なりました。再処理を受け付けるだけでは、結果を1回分に保てません。
条件:ローカルSQLiteに合成入力(同じIDで1を加算)を2回渡す。処理済みの判定は行わない。
- 観測:1回目の後 → 再処理の後
- DB反映数:1 → 2
確認の限界:通信障害やメッセージ配信回数を測った結果ではありません。
元の観測:結果JSONの case: A-no-dedup。observations の読戻し値を表示しています。
「処理済みの印を付ければ十分か」「DBの外への処理も守れるか」を、同じ入力を使った7ケースで調べました。 同じDB内の確定と、外部への効果を分けて読むための学習資料です。 SAA・SAPで再試行を考える手掛かりにできますが、AWSサービスの動作を実測した結果ではありません。
コードと実行記録で確かめる
同じ処理をやり直しても意図した結果が増えない性質を、ここでは冪等性として考えます。「処理済み」の印を付けるだけでは、欠落や二重反映を防げません。印とDBへの反映を別々に確定すると、途中で止まった位置によって結果が変わります。ローカルのSQLite実ファイルを別プロセスから更新し、停止後に同じイベントを再処理して確かめました。
実行日:2026年9月26日。架空の固定入力を使った実測です。AWSサービスの実機検証、実利用者の学習成果、人による専門家監修ではありません。採点付き問題ではなく、収録問題数には含めません。
demo-event-001と「1を加える」という内容。各ケースは空のDBから開始します。processed に処理済みID、effectsに反映を記録します。DB反映数は effects の合計です。BEGIN IMMEDIATEを使います。Gはこれに加え、DBトランザクションの外のファイルへ1行追記します。観測環境:Python 3.12.0・SQLite 3.42.0・macOS(Darwin 25.6.0)。SQLiteはDELETEジャーナル・synchronous=FULL・ロック待ち0秒。入力と仮説は実行前に固定し、各段階でDBを読み戻しました。
生成AIを用いた別工程でも、新しい出力先へ再実行し、同じ7ケースの結果と保存したDBを照合しました。同じ環境での再現確認です。
| 方式と中断条件 | DB反映数 | 外部行 |
|---|---|---|
| A:重複を判定しない | 1 → 2 | 0 → 0 |
| B:処理済み記録を先に確定 | 0 → 0 | 0 → 0 |
| C:DB反映を先に確定 | 1 → 2 | 0 → 0 |
| D:同じトランザクション・commit前に中断 | 0 → 1 | 0 → 0 |
| E:同じトランザクション・commit後に中断 | 1 → 1 | 0 → 0 |
| F:書込み競合後に明示的に再処理 | 0 → 1 → 1 | 0 → 0 → 0 |
| G:DBの外にも書き込み、commit前に中断 | 0 → 1 | 1 → 2 |
この実装では、同じ入力でも加算が重なりました。再処理を受け付けるだけでは、結果を1回分に保てません。
条件:ローカルSQLiteに合成入力(同じIDで1を加算)を2回渡す。処理済みの判定は行わない。
確認の限界:通信障害やメッセージ配信回数を測った結果ではありません。
元の観測:結果JSONの case: A-no-dedup。observations の読戻し値を表示しています。
印だけが残り、再処理が加算をスキップしました。重複を避けても、本来必要な更新を失う場合があります。
条件:ローカルSQLiteの合成入力(同じIDで1を加算)。処理済みIDだけを確定し、加算前に中断後、再処理する。
確認の限界:この停止点での欠落です。すべての障害を再現したわけではありません。
元の観測:結果JSONの case: B-marker-first。observations の読戻し値を表示しています。
印がないため、確定済みの加算をもう一度行いました。Bと順番を逆にするだけでは、欠落を重複に変えることになります。
条件:ローカルSQLiteの合成入力(同じIDで1を加算)。加算だけを確定し、処理済みIDを残す前に中断後、再処理する。
確認の限界:印と効果を別々に確定する、この実装と停止点での反例です。
元の観測:結果JSONの case: C-effect-first。observations の読戻し値を表示しています。
中断した変更は残らず、再処理で印と加算が一緒に確定しました。今回の入力と停止点では、欠落も二重反映も残りませんでした。
条件:ローカルSQLiteの合成入力(同じIDで1を加算)。印と加算を同じトランザクションに書き、commit前に中断後、再処理する。
確認の限界:確認したのはプロセス中断です。電源断・ディスク故障は未検証です。
元の観測:結果JSONの case: D-atomic-before-commit。observations の読戻し値を表示しています。
確定済みの印を見つけて加算をスキップし、DBの結果を維持しました。処理の完了が伝わらなくても、今回の再処理は二重反映しませんでした。
条件:ローカルSQLiteの合成入力(同じIDで1を加算)。印と加算をまとめてcommitし、完了を返す前に中断後、再処理する。
確認の限界:外部APIへの副作用や、以前の応答結果を返す仕組みは未検証です。
元の観測:結果JSONの case: E-atomic-after-commit。observations の読戻し値を表示しています。
別接続からは1番目の未確定の更新が見えません。2番目は競合で失敗し、commit後に呼び直すと処理済みの印を見つけました。
条件:ローカルSQLiteの合成入力(同じIDで1を加算)。1番目が未commit中に2番目はSQLITE_BUSY。commit後、明示的に再処理する。
確認の限界:自動再試行や、あらゆる並行実行順の安全性を確かめた結果ではありません。
元の観測:結果JSONの case: F-overlapping-workers。observations の読戻し値を表示しています。
DB外の追記はrollbackで消えず、再処理で増えました。このDBのrollbackは、別ファイルへの追記を取り消しません。
条件:ローカルSQLiteの合成入力(同じIDで1を加算)。DB内の印と加算に加え別ファイルへ追記し、commit前に中断後、再処理する。
確認の限界:外部行はローカルファイルの行数です。メール・決済・AWSでの実行数ではありません。
元の観測:結果JSONの case: G-side-effect-outside-db。observations の読戻し値を表示しています。
AWS公式は、SQS標準キューで同じメッセージを複数回受け取る場合に備え、アプリを冪等に設計するよう案内しています。根拠:標準キューの少なくとも1回の配信と冪等性。
SQSでは受信だけではメッセージは削除されず、処理・削除が完了しないまま可視性タイムアウトが切れると再び受信できます。標準キューでは、そのタイムアウト中にも重複配信が絶対にないとは保証されません。根拠:可視性タイムアウトと処理後の削除。
SAAで疎結合や再試行、SAPで複数処理の失敗を考えるときは、受信・業務DBの確定・メッセージ削除を別々の操作として並べてみてください。次に、どこで止まると重複または欠落するかを書きます。上のSQLiteの値を、SQSの配信回数やAWSの保証として読み替えないことが大切です。
上のAWS仕様2点の資料確認日:2026年9月26日。ローカル実験の観測とは別の根拠です。
公開したソースはPython 3.12以降の標準ライブラリを使います。ソースを保存したフォルダーから、新しい出力先を指定して実行します。ネットワーク通信、AWSアカウント、認証情報は使いません。今回確認した実行環境は上記の1環境で、他のOSや版すべての互換性は未確認です。
python3 -I retry-boundaries.py --output evidence/run-1既存の出力先は上書きしません。結果の countsは「処理済み行数・DB反映合計・外部ファイル行数」の順です。実行時刻やDBファイルのハッシュまで同じになることは要求せず、各段階の行と件数、子プロセスの終了・競合記録を比べてください。
配布するのはコードと観測記録です。実DBファイルは含みません。READMEのSQL確認は、自分で再現実行して生成したDBに対して行います。
検証したのは、この固定入力と7つの処理順、プロセス中断からの復帰です。電源断・ディスク故障、異なる入力内容に同じIDを使う場合、分散トランザクション、性能、AWS各サービスの配信保証は検証していません。学習時は、利用するAWSサービスの公式仕様と、アプリが責任を持つ範囲を別に確認してください。
制作・実行:PASS QUEST。説明と検証コードの作成には生成AIを使用しています。制作・確認範囲と訂正窓口から訂正を依頼できます。