確かめられるポストモーテムを書く
ポストモーテムとは、障害を振り返る短い文書です。時系列、原因、対策の一覧からなります。誰も確かめられない文書は、気持ちを残すだけなので、大切です。
図書館の費用の障害は終わりました。チームが文書にまとめ、署名の前に、小さなスクリプトが下書きをログと照らします。
このレッスンのゴール
メモ
私は、何が起き、なぜ起き、何を変えるかを書けます。
キーワード
| ことば | いみ | れい |
|---|---|---|
| ポストモーテム | 障害とその後を書いた文書 | |
| タイムライン | 障害の出来事を、時間の順に並べたもの | |
| 原因 | 起きた理由。ログで確かめられる言葉で書く | |
| 対策 | 担当者と期限のある変更 | |
| 確認方法 | 対策が効いたと見て取る方法 | 最大2回 |
学生が入力するセルは、このプレビューでは空白です。
タイムラインはログの時刻を使う
タイムラインは、何がいつ起きたかを順に並べます。時刻は、記録から写します。記憶では書きません。
良いタイムラインは、遅かった部分も含みます。原因が始まった時刻、誰かが気づいた時刻、終わった時刻です。その間の空きが、学びになります。
例: 図書館の出来事
| 時刻 | 出来事 |
|---|---|
| 10:55 | 長いファクトシートが公開される |
| 12:02 | 1時間ごとの費用アラートが鳴る |
| 12:20 | トレースから原因が見つかる |
| 12:35 | 試行の回数に上限が付く |
| 13:00 | 費用が上限の下に戻る |
学生が入力するセルは、このプレビューでは空白です。
ログが確かめられる原因
原因は、ログが正しいとも誤りとも言える一文で書きます。何が起き、どのリクエストで、なぜかを書きます。
「料金の質問が5回ずつ試された。40文字のチェックが通りようがなかったからだ」は確かめられます。「システムが過負荷だった」は確かめられません。どの記録もそれを裏づけないからです。
対策には担当者と確認方法がある
対策は、原因を直す、または空きを縮める変更です。どれにも、担当者、期限、確認方法があります。確認方法とは、対策が効いたときログに現れる数字です。
「もっと気をつける」には、どれもありません。「1リクエストの試行を最大2回にし、2日以内にログで確かめる」には、三つともあります。
よくある間違い
注意
ポストモーテムは、誰の責任かを書くものだと考える人が多いです。書くのは、システムのどこが失敗を許したかです。名前は、対策の担当者として横に書くだけにします。
下書きとログを書く(1)
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const fs = require(\"fs\");' 'const EVENTS = [' ' { time: \"10:55\", code: \"sheet_published\" },' ' { time: \"12:02\", code: \"alert_fired\" },' ' { time: \"12:20\", code: \"cause_found\" },' ' { time: \"12:35\", code: \"attempts_capped\" },' ' { time: \"13:00\", code: \"cost_normal\" },' '];' 'const DRAFT = {' ' timeline: [' ' { time: \"10:55\", code: \"sheet_published\" },' ' { time: \"12:02\", code: \"alert_fired\" },' ' { time: \"12:10\", code: \"cause_found\" },' ' { time: \"13:00\", code: \"cost_normal\" },' ' ],' > pm.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
下書きとログを書く(2)
docker exec -w /home/node/project agent sh -c "printf '%s\n' ' cause: \"料金の質問が5回ずつ試された。40文字のチェックが通りようがなかったからだ\",' ' actions: [' ' { what: \"試行を2回までに制限する\", owner: \"佐藤\", check: \"ログで、1リクエストの試行が最大2回\", days: 2 },' ' { what: \"シートをもっと丁寧に扱う\", owner: \"佐藤\", check: \"\", days: 5 },' ' { what: \"10分ごとにアラートを出す\", owner: \"\", check: \"急増から10分以内にアラートが鳴る\", days: 60 },' ' ],' '};' 'fs.writeFileSync(\"events.json\", JSON.stringify(EVENTS, null, 1));' 'fs.writeFileSync(\"postmortem.json\", JSON.stringify(DRAFT, null, 1));' >> pm.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
下書きのファイルを作る
docker exec -w /home/node/project agent node pm.jsここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
検査を書く(1)
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const fs = require(\"fs\");' 'const MAX_DAYS = 30;' 'function hasDigit(text) { return /[0-9]/.test(text); }' 'function run() {' ' const events = JSON.parse(fs.readFileSync(\"events.json\", \"utf8\"));' ' const pm = JSON.parse(fs.readFileSync(\"postmortem.json\", \"utf8\"));' ' const timeline = [];' ' const actions = [];' ' let last = \"\";' ' pm.timeline.forEach(function (entry, i) {' ' const found = events.find(function (e) { return e.code === entry.code; });' ' if (found === undefined) timeline.push(i + \":unknown_event\");' ' else if ((found.time === entry.time) === false) timeline.push(i + \":wrong_time\");' ' if (entry.time < last) timeline.push(i + \":out_of_order\");' ' last = entry.time;' ' });' > check-pm.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
検査を書く(2)
docker exec -w /home/node/project agent sh -c "printf '%s\n' ' events.forEach(function (e) {' ' if (pm.timeline.some(function (t) { return t.code === e.code; }) === false) timeline.push(\"missing:\" + e.code);' ' });' ' pm.actions.forEach(function (a, i) {' ' if (a.owner.trim() === \"\") actions.push(i + \":no_owner\");' ' if (a.check.trim() === \"\") actions.push(i + \":no_check\");' ' else if (hasDigit(a.check) === false) actions.push(i + \":no_number\");' ' if (a.days > MAX_DAYS) actions.push(i + \":too_late\");' ' });' ' console.log(\"タイムライン:\", timeline.join(\" \"));' ' console.log(\"対策:\", actions.join(\" \"));' ' const total = timeline.length + actions.length;' ' console.log(\"問題の数:\", total);' ' console.log(total === 0 ? \"ポストモーテムは完成しています。\" : \"ポストモーテムはまだ完成していません。\");' '}' 'module.exports = { run };' 'if (require.main === module) run();' >> check-pm.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
下書きを検査する
docker exec -w /home/node/project agent node check-pm.jsここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
検査の表示
| 行 | 意味 |
|---|---|
| タイムライン | 2:wrong_time missing:attempts_capped |
| 対策 | 1:no_check 2:no_owner 2:too_late |
| 問題の数 | 5 |
| 最後の行 | ポストモーテムはまだ完成していません。 |
学生が入力するセルは、このプレビューでは空白です。
修正を書く
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const fs = require(\"fs\");' 'const pm = JSON.parse(fs.readFileSync(\"postmortem.json\", \"utf8\"));' 'pm.timeline[2].time = \"12:20\"; // ログでは 12:20' 'pm.timeline.splice(3, 0, { time: \"12:35\", code: \"attempts_capped\" });' 'pm.actions[1].what = \"公開の前に、すべてのシートを40文字のチェックで試す\";' 'pm.actions[1].check = \"シートの公開前に、評価の全ケースが40文字のチェックを通る\";' 'pm.actions[2].owner = \"田中\";' 'pm.actions[2].days = 14;' 'fs.writeFileSync(\"postmortem.json\", JSON.stringify(pm, null, 1));' 'require(\"./check-pm\").run();' > fix-pm.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
下書きを直して、もう一度検査する
docker exec -w /home/node/project agent node fix-pm.jsここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。