ANTIGRAVITY LABEN
記事一覧/Agents & Manager
Agents & Manager/2026-07-12上級

エージェントの時計設計 — 単調時計と壁時計を分けて長時間運用を守る

スケジュール実行や夜間の長時間エージェント運用で、タイムアウト・リトライ間隔・レート制限窓を壁時計で計算すると静かに壊れます。単調時計と壁時計の役割を分ける小さな Clock 抽象と、決定表・テスト可能な実装を交えて設計を整理します。

エージェント57長時間運用単調時計タイムアウト設計2スケジュール実行8信頼性設計8

プレミアム記事

ある朝、夜間に走らせていたエージェントのログを開いて、手が止まりました。深夜2時台に始まった処理が「4時間14分経過したのでタイムアウトしました」と自らを打ち切っていたのです。実際の作業内容は10分ほどで終わるはずのものでした。原因を追ってようやく腑に落ちたのは、途中でマシンがスリープに入り、復帰後に壁時計(現在時刻)の差分をそのまま「経過時間」として扱っていたことでした。処理は健全だったのに、時計の読み方だけが間違っていたのです。

個人開発でアプリを作りながら、複数の保守作業を夜間のスケジュール実行にまとめて任せていると、この種の「時計に起因する誤動作」は避けて通れません。エージェントに長い時間を預けるほど、時刻をどう測るかという地味な設計が、安心して任せられるかどうかを静かに左右します。ここでは、単調時計(monotonic clock)と壁時計(wall clock)を意図的に分けて扱う小さな設計を、動くコードと決定表を交えて整理してまいります。

なぜ壁時計での経過時間計算は壊れるのか

まず、多くのコードが暗黙に採用している書き方を見てみます。

const start = Date.now();
await doWork();
const elapsedMs = Date.now() - start;
if (elapsedMs > 30_000) {
  throw new Error("処理が30秒を超えました");
}

一見すると素直で、短時間の処理ではまず問題になりません。しかし Date.now() が返すのは壁時計、つまり「いま何時か」という人間向けの時刻です。壁時計は、私たちの都合とは無関係に動きます。

具体的には、次のような場面で差分が実際の所要時間からずれます。

事象壁時計への影響経過時間計算で起きること
NTPによる時刻補正数百msから数秒、前後に飛ぶ経過が負の値になる、または急増する
VMやノートPCのサスペンド/復帰停止していた分だけ一気に進む健全な処理を「タイムアウト」と誤判定
夏時間(DST)の切り替え1時間進む/戻る深夜帯の処理で±1時間の誤差
手動・同期による時刻変更任意に飛ぶリトライ間隔やレート制限窓が破綻

特に厄介なのは、時刻が戻るケースです。NTPが壁時計を過去に引き戻すと、Date.now() - start が負になり、elapsedMs > 30_000 は永遠に成立しません。タイムアウトが効かないまま、エージェントが待ち続けます。逆に、サスペンドから復帰した直後は差分が跳ね上がり、まだ何も終わっていないのに打ち切りが走ります。どちらも、ログには「タイムアウト」や「無限待機」としか残らず、真因にたどり着くまで時間を溶かします。ここが最初の注意点です。

単調時計という選択肢

この問題の中心は、「所要時間の測定」に「現在時刻の表示」用の時計を流用していることにあります。所要時間には、単調時計を使うのが正解です。

単調時計は、後戻りしないことを保証された時計です。NTPが補正しても、DSTが切り替わっても、値は必ず増加方向にしか進みません。Node.js では process.hrtime.bigint() が、ブラウザや Deno では performance.now() がこれにあたります。返すのは「いつ」ではなく「起点からどれだけ進んだか」という相対量で、人間向けの時刻としては読めませんが、差分を取れば正確な所要時間になります。

const start = process.hrtime.bigint();
await doWork();
const elapsedMs = Number(process.hrtime.bigint() - start) / 1_000_000;
if (elapsedMs > 30_000) {
  throw new Error("処理が30秒を超えました");
}

見た目の変化はわずかですが、意味は大きく変わりました。この elapsedMs は、マシンがスリープしていようがNTPが暴れていようが、実際に経過した実時間を表します。ただし単調時計は「起点からの相対値」なので、プロセスをまたいだり、ログに人間が読める時刻を残したりする用途には使えません。この場合は、役割分担の設計が必要になります。

ここまでお読みいただきありがとうございます。

この記事の続きを読む

この先には、実装コードやベンチマーク結果など、実務でお役に立てる内容をご用意しています。このサイトは広告を掲載しておらず、サーバーや開発にかかる費用はメンバーの皆様のご支援で成り立っています。もしお役に立てていましたら、ご支援いただけますと大変ありがたいです。

この記事で得られること
タイムアウト・バックオフ・レート制限窓を壁時計で測ると、VMのサスペンドやNTP補正で静かに破綻する理由
所要時間は単調時計、記録と次回起動は壁時計へ振り分ける小さな Clock 抽象の実装
用途ごとにどちらの時計を使うかを一望できる決定表と、決定論的にテストする方法
Stripe による安全な決済 · いつでもキャンセル可能

この記事を購入する

この先の内容をすべてお読みいただけます。一度のご購入で、いつでも何度でもアクセスできます。このサイトは広告を掲載しておらず、皆さまのご支援がサーバー費用などの運営を支えています。

または
メンバーシップなら全記事が読み放題 →
シェア

お読みいただきありがとうございます

Antigravity Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

関連記事

Agents & Manager2026-06-20
失敗したエージェントジョブを取りこぼさない — デッドレターと再投入の設計
スケジュール実行のエージェントが夜間に失敗したまま消えていく問題を、デッドレター退避と段階的な再投入で防ぐ設計を、複数サイトを自動運用する個人開発の現場からまとめます。
Agents & Manager2026-06-21
無人エージェントの実行ログを、ディスクを溢れさせずに後から追える形で残す
スケジュール実行のエージェントは、落ちた理由を後から追えなければ直せません。実行ログをディスクを溢れさせずに残すため、3層保持・スキーマ版付与・圧縮ジョブで設計する方法を、複数サイトを自動運用する個人開発の現場からまとめます。
Agents & Manager2026-07-12
書き込みより怖いのは到達先だった — エージェントの外向き通信を許可ホストだけに絞る
エージェントに実作業を委ねるとき、私が一番警戒しているのはファイルの書き換えではなく、どこへ通信するかです。到達先を deny-by-default で絞る小さなゲートの実装と、21晩の無人運用で拾った通信の内訳をまとめました。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →