クリーム色の背景、色付き表示、高コントラスト、大きな文字のほうが読みやすいですか?配色と文字を選ぶと、すべてのページに一度で反映されます。

無料レッスン

長い処理のチェックポイント

このレッスンのあとで: 長い処理を、安全に止めて再開できるようにできる。

60分のレッスンコマンド4件AI コーディングエージェントのラボ:opencode でコードを説明・修正し、その結果を確かめる

二重に請求してしまった処理

チェックポイントとは、すでに終わった仕事を保存した記録です。これがあれば、長い処理を止めても、最初からやり直さずに再開できます。エージェントは数分から数時間動き、プロセスは途中で落ちます。

ある処理が5件の注文に請求しました。3件目で落ち、最初からやり直しました。2人の客が二重に支払いました。

このレッスンのゴール

メモ

長い処理を、安全に止めて再開できるようにできる。

キーワード

ことばいみれい
チェックポイント終わった仕事を保存した記録
冪等2回実行しても、効果が1回分で済むこと
再開最後のチェックポイントから続けること
副作用プログラムの外に起きる変化請求
イベントログ起きたことを順に並べた一覧

学生が入力するセルは、このプレビューでは空白です。

チェックポイントは終わったことを示す

ステップが終わるたびに、その名前をファイルか表に書きます。開始するときにその記録を読み、すでに終わったものを飛ばします。

ステップの前に開始、後に完了を書きます。すると再開のとき、一度も始まっていないステップと、途中で切れたステップを区別できます。

例: 障害が起きる場所

障害の場所記録の内容再開のとき
ステップの開始前そのステップのことは何もない実行する
ステップの中、効果の前開始再試行する
効果のあと、完了の前開始再試行する。効果が繰り返される
完了のあと完了飛ばす

学生が入力するセルは、このプレビューでは空白です。

再開できる処理を書く(1)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const fs = require(\"fs\");' 'const CHECK = \"demo/checkpoint.json\";' 'const LOG = \"demo/charges.log\";' 'const orders = [\"O1\", \"O2\", \"O3\", \"O4\", \"O5\"];' 'const crashAt = process.argv[2];' 'fs.mkdirSync(\"demo\", { recursive: true });' 'function load() {' '  try { return JSON.parse(fs.readFileSync(CHECK, \"utf8\")); } catch (error) { return { done: [], started: null }; }' '}' 'function save(state) { fs.writeFileSync(CHECK, JSON.stringify(state)); }' 'function charge(id) {' '  const seen = fs.existsSync(LOG) ? fs.readFileSync(LOG, \"utf8\").split(\"\n\") : [];' '  if (seen.indexOf(id) >= 0) { console.log(id + \": 請求済みなので、もう一度は請求しません\"); return; }' '  fs.appendFileSync(LOG, id + \"\n\");' '}' > batch1.js"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

再開できる処理を書く(2)

コマンド
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const state = load();' 'console.log(\"ここまでに完了: \" + (state.done.join(\",\") || \"なし\") + \"。中断した場所: \" + state.started);' 'for (const id of orders) {' '  if (state.done.indexOf(id) >= 0) { console.log(id + \": 完了済みなので飛ばします\"); continue; }' '  state.started = id;' '  save(state);' '  charge(id);' '  if (id === crashAt) { console.log(id + \" の作業中に障害が起きました\"); process.exit(1); }' '  state.done.push(id);' '  state.started = null;' '  save(state);' '  console.log(id + \": 完了\");' '}' 'console.log(\"終了。請求の回数: \" + fs.readFileSync(LOG, \"utf8\").trim().split(\"\n\").length);' >> batch1.js"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

最初から実行して O3 で落とす

コマンド
docker exec -w /home/node/project agent sh -c "rm -rf demo; node batch1.js O3"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

もう一度実行して再開する

コマンド
docker exec -w /home/node/project agent node batch1.js

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

出力の一例

実行表示される内容
1回目O1 完了、O2 完了、そのあと O3 の作業中に障害
2回目中断した場所は O3、O1 と O2 は飛ばされる
2回目の O3請求済みなので、もう一度は請求せず、そのあと完了
最後の行終了。請求の回数: 5。注文ごとに1回

学生が入力するセルは、このプレビューでは空白です。

各ステップを、繰り返しても安全にする

ステップが冪等とは、2回実行しても、1回実行したのと同じ効果になることです。効果ごとに、注文番号のようなキーを付けます。動く前に、そのキーがすでに使われたかを確かめます。

外部のサービスが対応しているなら、リクエストにキーを付けて送ります。サービス側が、繰り返しを断れます。

よくある間違い

注意

「チェックポイントがあれば、再試行は安全だ」と考える人が多くいます。チェックポイントは、終わったことを記録するだけです。効果のあとで切れたステップは再実行されるので、ステップ自体が繰り返しに安全でなければなりません。記録と冪等なステップを、両方使います。

このラボとソースについて: AI コーディングエージェントのラボ:opencode でコードを説明・修正し、その結果を確かめる

授業で使いますか?このモジュールを学生に割り当てると、教員用ガイド、自動採点つきの課題、学生ごとのラボを使えます。