SOARの再試行とエラー処理
分岐、承認、実行、再試行、復旧の状態を記録とデータの両方から確認します。
説明
自動対応は処理の途中で失敗したり、成功応答が届かず再実行されたりします。同じ要求を二度適用しない工夫と、別の更新を壊さずに戻す条件が必要です。
SQLite内の状態更新を使って、コミット前の例外、同じジョブの再実行、権限不足、世代を照合した補償処理を順に試します。外部APIを含む手順では、同じDBトランザクションで一括取消しできない範囲もあります。
分岐、承認、実行、再試行、復旧の状態を記録とデータの両方から確認します。
1承認済みのジョブを用意する
このページだけでws7の世代1から始めます。
from sp08 import *
from sp02 import show
lab=Workflow()
print(lab.trigger('j7','ws7'))
print(lab.approve承認済みのジョブを用意する('j7','responder'))ジョブはapprovedです。次に更新後・コミット前の失敗を発生させます。
2コミット前の例外でロールバックする
failは検証用に例外を発生させる引数です。
print(lab.execute('j7','connector',fail=Trueコミット前の例外でロールバックする))
show(lab.db,"SELECT isolated,version FROM asset WHERE id='ws7'")
show(lab.db,"SELECT COUNT(*) AS effects FROM effect")rolled_back、状態0、世代1、適用記録0です。同じDBのトランザクション内の変更が取り消されています。
3再試行で一度だけ適用する
同じジョブを正常条件で実行します。
print(lab.execute再試行で一度だけ適用する('j7','connector'))
print(lab.execute('j7','connector'))
show(lab.db,"SELECT isolated,version FROM asset WHERE id='ws7'")appliedの後はalready_appliedです。世代は2のままです。要求IDに対応する適用記録が二重実行を防いでいます。
4結果が保存されたことを確認する
ジョブ、変更前の値、適用後の世代を表示します。
show結果が保存されたことを確認する(lab.db,"SELECT * FROM effect")
show(lab.db,"SELECT job,result FROM audit ORDER BY seq")j7の適用記録は1行です。応答を見失った場合も、同じIDの保存済み結果から確認できます。
5復旧を許可する主体を確認する
connectorによる復旧とresponderによる復旧を比較します。
print(lab.compensate復旧を許可する主体を確認する('j7','connector'))
print(lab.compensate('j7','responder'))
show(lab.db,"SELECT isolated,version FROM asset WHERE id='ws7'")復旧後は状態0、世代3です。元の値へ戻しても世代は進め、途中に操作があったことを保持します。
6同じ復旧を再実行しても上書きしない
適用直後の世代2を条件にするため、二度目は不一致になります。
print(lab.compensate同じ復旧を再実行しても上書きしない('j7','responder'))
show(lab.db,"SELECT job,result FROM audit ORDER BY seq")version_conflictです。既に別の状態へ進んだ対象を、古い適用記録だけで上書きしません。
7承認後に対象が変わった場合を拒否する
新しいジョブを承認した後、資産の世代を別操作で進めます。
print(lab.trigger('j8','ws7'))
print(lab.approve('j8','responder'))
lab.db.execute("UPDATE asset SET version=4 WHERE id='ws7'");lab.db.commit()
print(lab.execute承認後に対象が変わった場合を拒否する('j8','connector'))
show(lab.db,"SELECT isolated,version FROM asset WHERE id='ws7'")version_conflictとなり状態0を保持します。承認の根拠が古くなったら情報を再取得して判断し直します。
まとめ
ジョブIDに対する適用記録で再試行を扱います。
トランザクションで戻せる範囲を確認します。
補償処理には更新世代と権限の確認が必要です。
操作履歴と解説を振り返れます。
Python 3.15 / SQLiteの対応手順モデル
from sp08 import *
from sp02 import show
lab=Workflow()
print(lab.trigger('j7','ws7'))
print(lab.approve('j7','responder'))awaiting_approval approved
print(lab.execute('j7','connector',fail=True))
show(lab.db,"SELECT isolated,version FROM asset WHERE id='ws7'")
show(lab.db,"SELECT COUNT(*) AS effects FROM effect")rolled_back isolated | version 0 | 1 effects 0
print(lab.execute('j7','connector'))
print(lab.execute('j7','connector'))
show(lab.db,"SELECT isolated,version FROM asset WHERE id='ws7'")applied already_applied isolated | version 1 | 2
show(lab.db,"SELECT * FROM effect")
show(lab.db,"SELECT job,result FROM audit ORDER BY seq")job | asset | before_value | after_version j7 | ws7 | 0 | 2 job | result j7 | applied
print(lab.compensate('j7','connector'))
print(lab.compensate('j7','responder'))
show(lab.db,"SELECT isolated,version FROM asset WHERE id='ws7'")permission_denied compensated isolated | version 0 | 3
print(lab.compensate('j7','responder'))
show(lab.db,"SELECT job,result FROM audit ORDER BY seq")version_conflict job | result j7 | applied j7 | compensated
print(lab.trigger('j8','ws7'))
print(lab.approve('j8','responder'))
lab.db.execute("UPDATE asset SET version=4 WHERE id='ws7'");lab.db.commit()
print(lab.execute('j8','connector'))
show(lab.db,"SELECT isolated,version FROM asset WHERE id='ws7'")awaiting_approval approved version_conflict isolated | version 0 | 4
演習完了