3行まとめ
- 記事本文をブラウザ上の共同編集ドキュメントへ自動入力させたところ、同じ節が二重・三重に並びました。
- 原因は、送信が完了しても画面への反映が終わっていない状態を「失敗」と判断して送り直したことでした。
- 自動化に再試行を組み込む前に、その操作が二度実行されても問題ない形かどうかを決めておく必要があります。
はじめに
社内のナレッジ共有用に、手元で書いた記事をブラウザ上の共同編集ドキュメントへ流し込む処理を組んでいました。見出しと段落を含む本文をまとめて投入するだけの、単純な作業です。
一度目の実行では、投入した直後の画面に何も増えませんでした。エラーも出ていません。処理は正常終了しています。反映されなかったのだろうと判断し、同じ処理をもう一度実行しました。
数十秒後、本文を確認して状況が分かりました。
- 同じ見出しと段落が二重、箇所によっては三重に並んでいる
- 節の順序が原稿と入れ替わっている
- 一部の段落だけが欠落している
- エディタ側にエラーは表示されておらず、処理も正常終了している
投入は失敗していませんでした。一度目の送信も、二度目の送信も、どちらも通っていたのです。
送信の完了と、反映の完了は別のできごと
共同編集に対応したドキュメントは、入力をその場で確定させていません。手元の操作をいったん受け取り、サーバー側で他の編集と突き合わせたうえで、最終的な並び順を決めて画面に返します。手元で完結する編集とは、ここが決定的に違います。
↓
その場で確定
↓
画面に反映される
↓
送信の完了=反映の完了
↓
サーバーで他の編集と突き合わせ
↓
並び順を決めて返す
↓
送信の完了≠反映の完了
この構造のため、送信直後の画面はまだ何も変わっていないことがあります。私が「失敗した」と判断した状態は、実際には順番待ちでした。
同じ理由で、まとめて連続送信した場合の並び順も保証されません。送った順に処理される前提で節を分割して投入すると、突き合わせの結果として順序が入れ替わります。原稿と違う並びになっていたのは、これが原因でした。
最も危険な操作は「反映がないので、もう一度送る」
ここが今回の本題です。反映が確認できないときに同じ処理を再実行するのは、一見すると穏当な対処に見えます。実際には、失敗を回復する操作ではなく、成功した操作をもう一度足す操作でした。
見直したのは、再試行の入れ方そのものです。処理の内容は変えず、送る回数と確認の順序だけを次のように決めました。
| やっていたこと | 変更後 |
|---|---|
| 節ごとに分割して連続送信 | 全文を1回で送る(分割数を減らすほど乱れない) |
| 送信後すぐ次の処理へ進む | 本文の実体を読み取り、増えたことを確認してから次へ |
| 反映がなければ同じ処理を再実行 | 原因(送信先の指定ずれ等)を直したうえで、1回だけやり直す |
| 結果の確認は目視 | 見出しの数と重複の有無を機械的に照合する |
同じ話は、投入先がドキュメントでなくても成り立ちます。応答が返る前に切れた登録処理、送信済みか判別できないメール、途中で落ちたデータ連携。いずれも「もう一度実行する」が安全かどうかは、相手側が二度目を無視してくれるかどうかで決まります。無視してくれない相手に自動再試行を付けると、失敗ではなく重複という形で表に出ます。
結論
今回の重複は、通信の失敗でも自動化の限界でもなく、再試行してよいかどうかを決めずに再試行したことが原因でした。自動化を組むときに書き足すべきなのは、失敗時にもう一度送る処理ではなく、送った結果が本当に届いたかを読み取る処理です。確認する手段がない操作は、そもそも二度実行しない前提で設計する。反映を待てずに送り直した数十秒が、本文の作り直しという形で返ってきました。
まとめ
- 送信が完了したことと、相手側に反映されたことは別に扱う。前者だけで成否を判断しない。
- 反映を確認できない操作に自動再試行を付けない。付けるなら、二度実行しても結果が変わらない形にしてから付ける。
- 共同編集や非同期処理では、送った順に処理される保証がない。順序が意味を持つ投入は、分割せず1回で渡す。
- やり直す前に、反映されていない原因を1つに絞る。同じ操作の繰り返しは、原因を切り分ける行為ではない。
- 確認は目視ではなく機械的な照合にする。重複は目で追うと見落としやすい。