Claude Media
Claude Codeのhold-idle-fileで残プロセス中のセッションを保持する

Claude Codeのhold-idle-fileで残プロセス中のセッションを保持する

セルフホストRunnerのアイドル解放を、ホスト上の残プロセスがある間だけ止める--hold-idle-fileの設定手順。touchの間隔、--max-hold-minの上限、保持が切れる条件をまとめます。

--hold-idle-fileは、セルフホストRunnerがアイドルセッションを解放する時刻を、ホスト側のファイル更新で遅らせるフラグです。セッションがnohupで夜間ビルドなどを走らせたまま黙った場合に、そのプロセスが終わるまでセッションをRunnerに留められます。Claude Code v2.1.311で追加されました。

使い方は短く言えば、Runnerにファイルのパスを渡し、ホストの側から3分より短い間隔でそのファイルをtouchし続けるだけです。ただし、置き場所の権限、--max-hold-minの置き方、止めどきの判定で外すと「保持されない」か「いつまでも解放されない」のどちらかになります。この記事は、その3点を中心に設定から確認まで通します。

--hold-idle-fileは何を遅らせるのか

固定フリートのRunnerは、既定ではターンが終わったセッションもスロットを持ち続けます。これを避けるのが--release-idle-session-minで、指定した分数だけアイドルが続いたセッションを解放します。解放されたセッションは、次のメッセージで再開しますが、pushしていない作業は失われます。

ここで困るのが、セッションがnohupジョブなどをホストに残して黙ったケースです。Claude側は待機中に見えても、ホストでは処理が走っています。--hold-idle-fileは、その間だけ解放を保留する仕組みです。

関係するフラグは3つです。

フラグ環境変数既定値役割
--hold-idle-file <path>環境変数SELF_HOSTED_RUNNER_HOLD_IDLE_FILE既定値未設定役割ホストが更新し続けるファイル。更新が続く間、アイドルセッションを保持する
--max-hold-min <n>環境変数SELF_HOSTED_RUNNER_MAX_HOLD_MS既定値1440(1日)役割保持の上限。セッションがアイドルになった時点から数える
--release-idle-session-min <n>環境変数SELF_HOSTED_RUNNER_SESSION_IDLE_MS既定値0(無効)役割アイドル解放までの分数。保持の対象になる解放はこれ

3つとも、Claude Code v2.1.311以降が前提です。--release-idle-session-minが0のままだと、そもそも解放が起きないので保持の出番もありません。フラグ全体の一覧はClaude Codeセルフホスト環境のCLIフラグ・メトリクスリファレンスにあります。

設定する4つの手順

前提は、ホスト上で非rootのRunnerを動かしていることです。Runnerがrootで動いていると、セッションがそのファイルを自分でtouchできてしまいます。専用ユーザーでRunnerを動かすところから始めます。

手順

設定から確認までの流れ

  1. 1

    ファイルの置き場所を決める

    ローカルの通常ファイルを選びます。例は/var/lib/claude-hold/hold-idleです。親ディレクトリを含め、セッションが書き込めない場所に置きます。

  2. 2

    Runnerを起動する

    --hold-idle-file、--release-idle-session-min、--max-hold-minの3つを渡します。

  3. 3

    残プロセスがある間、touchし続ける

    ディレクトリの所有者として、3分より短い間隔でtouchします。

  4. 4

    保持を確かめる

    ファイルの更新時刻と、Runnerのログのidle release heldを見ます。

1. 置き場所はセッションから書けない場所にする

RunnerとセッションはOSユーザーを共有します。同じユーザーが書けるディレクトリにファイルを置くと、セッション自身がtouchして居座れてしまいます。そこで、先に別ユーザー(例はroot)所有、モード755でディレクトリを作ります。

sudo mkdir -p /var/lib/claude-hold
sudo chown root:root /var/lib/claude-hold
sudo chmod 755 /var/lib/claude-hold

この3行はディレクトリの条件を満たす書き方の一例です。親ディレクトリ(/var/lib)もセッションのユーザーが書けないことを確かめてください。

2. Runnerを3つのフラグ付きで起動する

--max-hold-minは保持の上限で、既定は1日です。--release-idle-session-minより大きい値にしないと、何も保持されません。次の例は、30分で解放し、保持中でもアイドルから4時間で解放します。

claude self-hosted-runner \
  --environment-secret-file /etc/claude/environment-secret \
  --release-idle-session-min 30 \
  --hold-idle-file /var/lib/claude-hold/hold-idle \
  --max-hold-min 240

3. 残プロセスの間だけtouchする

ファイルの最初のtouchが作成を兼ねます。rootのcrontabに次の1行を足す例が示されています。

* * * * * pgrep -x nightly-build > /dev/null && touch /var/lib/claude-hold/hold-idle

毎分実行し、nightly-buildという名前のプロセスが動いている間だけtouchします。pgrepの部分は、セッションが残したものをホストが見つける方法に置き換えます。

4. 更新時刻とログで保持を確かめる

プロセスが動いている間は、ファイルの更新時刻が3分以内に保たれているはずです。次のコマンドは、直近3分以内に更新されていればパスを表示し、古ければ何も出しません(手元の確認用の一例です)。

find /var/lib/claude-hold/hold-idle -mmin -3

セッションのアイドル時間が尽きたら、Runnerのログにidle release heldの行が出ます。出ない場合は、起動時に出るwatchdog configの行にあるleftover-hold=を読みます。そこに、対象のファイルと上限、または何も保持されない理由が書かれます。

保持が続く時間と終わる時間

保持の長さは、touchの有無と上限の2つで決まります。数字を並べます。

数字

3つの時間の関係

  • touchの鮮度

    3分

    最後のtouchから3分で保持が終わる

  • 解放までの余白

    約1分

    保持が終わってからログに出るまで

  • 上限の既定

    1日

    --max-hold-minの既定は1440分

最後のtouchから3分たつと保持が終わり、そこからおよそ1分以内にidle release no longer heldがログに出て、Runnerがセッションを解放します。たとえば先の設定で、セッションがアイドルになってから100分後にジョブが終わり、その直前が最後のtouchなら、解放は103分後からおよそ104分後の見当です(公式の秒数からの計算例で、実測ではありません)。

cronを毎分にしているのは、この3分に収めるためです。間隔を5分にすると、touchとtouchの間に保持が切れます。

保持が切れる条件

ファイルを更新し続けていても、保持は終わることがあります。

  • 上限に達した: --max-hold-minが尽きる。長く保持したいなら値を上げる
  • 強制解放の期限が来た: --retire-at、--defer-shutdown-max-min、--kill-session-after-minのいずれかを設定していて、その期限が到来する。長く保持したいなら、より遅い期限にする

つまり、保持は解放を遅らせるだけで、期限つきの停止指示には勝てません。--kill-session-after-minはアイドルにならないセッションの安全網でもあるので、保持を使うときは、保持の上限より遅い値にしておくと、保持が先に切れる順序になります。

また、--max-hold-minに--release-idle-session-min以下の値を入れると何も保持されず、0にすると保持機能そのものが止まります。

効いていないときの切り分け

切り分け

保持されないときの確認順

  1. QRunnerはv2.1.311以降で、3つのフラグが揃っているか?
    答えがいいえのとき

    フラグを足してRunnerを再起動します。

    答えがはい
  2. Q--max-hold-minは--release-idle-session-minより大きいか?
    答えがいいえのとき

    上限を引き上げます。以下の値では何も保持されません。

    答えがはい
  3. Qファイルの更新時刻は3分以内に保たれているか?
    答えがいいえのとき

    cronの間隔、実行ユーザー、パスの書き込み権限を見ます。

    答えがはい
  4. Qidle release heldがログに出ているか?
    答えがいいえのとき

    起動時のwatchdog configにあるleftover-hold=を読みます。

    答えがはい

保持の設定は有効です

残る要因は強制解放の期限です。--retire-atなどが近づいていないか見ます。

詰まりやすい2点

落とし穴

残プロセスが終わっても判定が止まらない

touchの条件が、終わったジョブに反応し続けると、アイドルのセッションはすべて上限まで保持されます。pgrepのような判定は、ジョブの終了で確実に不一致になるものにします。

落とし穴

ファイルをセッションが書ける場所に置く

セッションがファイルを更新できると、残プロセスがなくても自分で保持を延ばせます。Runnerをrootで動かしている場合も同じ理由で、専用ユーザーに分けてから使います。

保持を使う場面と使わない場面

--release-idle-session-minを入れたのは、アイドルのセッションがスロットを占めて、ほかのオーナーのセッションがキューに残る状況を避けるためでした。クラウド側のスケジュールタスクが実行ごとに新しいセッションを作る運用では、アイドルのセッションが全スロットを埋めることがあります。解放はその対策です。

保持はその逆向きの例外です。解放の時刻を遅らせるので、スロットの回転は悪くなります。保持を入れる価値があるのは、ホストに残るプロセスの完了を待つ価値が、スロットの占有より大きいときです。たとえば長時間のビルドやデータ処理をnohupで投げたあと、結果をセッションに戻したい場合です。逆に、プロセスが残らないセッションには何も起きないので、設定を入れても害はありません。

保持の有無は、claude_code_self_hosted_runner_session_idle_secondsのメトリクスでも追えます。セッションごとの系列があり、0ならそのセッションは作業中、それ以外はアイドルになってからの秒数です。保持中のセッションがどう見えるかは、手元のRunnerで一度確かめておくと安心です。

上限で解放されたときの作業

保持が上限や強制解放で終わると、セッションは解放されます。解放されたセッションは、ユーザーの次のメッセージで新しいRunnerに再開されますが、そのRunnerは開始ブランチから改めてクローンするため、pushしていない作業は残りません。

コミット済みの作業を守るには、環境内のすべてのRunnerに--push-outcome-on-releaseを設定します。付けたRunnerは、解放の前にoutcomeブランチをベストエフォートでpushし、再開したセッションはそのコミットから始まります。付けていないRunnerに再開されると、開始ブランチからになる点に注意が必要です。有効にする前に、元のリモートでclaude/*のrefにpushできる人を絞っておきます。再開時にRunnerは、以前pushされたブランチを、誰がpushしたかを確認せずに取得するためです。コミットしていない変更は、このフラグでも守られません。

つまり、保持は「待てる時間を延ばす」ものであって、「作業を守る」ものではありません。上限を越えそうなジョブでは、待たせる時間よりも、途中経過をpushする運用のほうが効きます。

まとめ

--hold-idle-fileは、アイドル解放を残プロセスの有無に連動させる一手です。成立する条件は、セッションから書けないパスと、3分より短いtouch間隔、--release-idle-session-minより大きい--max-hold-minの3つです。

アイドル解放そのものの設計はClaude Codeセルフホスト環境の本番運用で、Runner自体の位置づけはself-hosted-runnerの解説で扱っています。保持を入れる前に、まず--release-idle-session-minだけでスロットが空くかを試し、残プロセスで困った時点で足す順序が無理のない進め方です。

参照した一次ソース

この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。

  1. code.claude.com/docs/en/self-hosted-environments-deploy
  2. code.claude.com/docs/en/self-hosted-environments-reference
  3. code.claude.com/docs/en/changelog
この記事を共有:XはてブLinkedIn