一覧SP-08-2 · SOAR:対応手順の自動化

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の対応手順モデル

1
from sp08 import * from sp02 import show lab=Workflow() print(lab.trigger('j7','ws7')) print(lab.approve('j7','responder'))
awaiting_approval
approved
2
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
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
isolated | version
1 | 2
4
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
5
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
6
print(lab.compensate('j7','responder')) show(lab.db,"SELECT job,result FROM audit ORDER BY seq")
version_conflict
job | result
j7 | applied
j7 | compensated
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'")
awaiting_approval
approved
version_conflict
isolated | version
0 | 4

演習完了