M.

PC のスリープを Claude Code に任せる(長いジョブの間は止めて、終わったら眠らせる)

ローカルの GPU で、画像の大量生成や LoRA の学習を Claude Code に回してもらうことがよくあります。数時間かかるので、寝る前に始めて朝に結果を見るのが理想です。

ところが朝起きると、ジョブが途中で止まっていることがありました。原因は PC のスリープ です。

  • 画像1000枚の生成が、781枚目のあたりで止まっていた
  • LoRA の学習が、夜中の3:00から10:20まで止まっていた

そこで、スリープまわりを Claude Code に任せることにしました。やってもらっていることは2つです。

  1. ジョブが動いている間だけ、スリープを止める
  2. 作業が終わったら、PC をスリープさせる

環境:Windows 10 / Git Bash / Claude Code 2.1.302

1. ジョブの間だけスリープを止める

最初に試してうまくいかなかったこと

Claude にいくつか方法を試してもらいましたが、最初はどれもいまひとつでした。

方法結果
電源設定(powercfg)でスリープを「なし」にする効くが、戻し忘れるとずっとスリープしなくなる
powercfg /requestsoverride で特定のプロセスだけ例外にする管理者権限が必要で、Claude からは実行できない
定期的にマウスを 1px 動かすPowerShell 7 では System.Windows.Forms を読み込めず失敗
別ウィンドウの PowerShell でスリープを止め続ける自分でウィンドウを閉じてしまい、いつの間にか止まっていた

落ち着いた方法:SetThreadExecutionState と PID の見張り

最終的には、Windows の API SetThreadExecutionState を Python から呼ぶ小さなスクリプトになりました。管理者権限は要りません。

"""指定した PID のプロセスが動いている間、スリープを止める。
使い方: python keep_awake.py <見張るPID>
"""
import ctypes
import subprocess
import sys
import time

ES_CONTINUOUS = 0x80000000
ES_SYSTEM_REQUIRED = 0x00000001

target_pid = int(sys.argv[1])
kernel32 = ctypes.windll.kernel32

try:
    while True:
        kernel32.SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED)
        time.sleep(30)
        r = subprocess.run(["tasklist", "/FI", f"PID eq {target_pid}"],
                           capture_output=True, text=True)
        if str(target_pid) not in r.stdout:
            break  # ジョブが終わったら抜ける
finally:
    kernel32.SetThreadExecutionState(ES_CONTINUOUS)  # スリープを許可に戻す

ポイントは2つです。

  • 見張るジョブが終わったら、自分も終わる。スリープを止めっぱなしにしない
  • スクリプトが落ちても、Windows が自動で解除する。SetThreadExecutionState の効果は呼んだプロセスが終わると消えるので、電源設定を書き換える方法より後始末が楽です

見張る PID がずれる問題

venv の python.exe から起動すると、実際に計算しているのは venv の python が起動した 子プロセス(本体の python) でした。最初に起動したプロセスの PID を見張ると、ジョブの実体とずれてしまいます。

そこで、ジョブの起動からスリープ防止までを1つのラッパーにまとめてもらいました。やっていることは次の流れです。

  1. ジョブをバックグラウンドで起動する
  2. 15秒待ってから、コマンドラインにスクリプト名を含む python.exe を探し、その PID を取る
  3. その PID を keep_awake.py に渡して起動する

LoRA の学習では、PID の代わりに accelerate.exe というプロセス名で見張る版にしています。どちらも「スリープ防止は今後も使うので、定型作業としてスクリプト化しておいて」と頼んで作ってもらいました。

失敗:スリープ防止が3日間残っていた

しばらくして、操作しないまま放っておいても PC が自動でスリープしなくなっていることに気づきました。Claude に調べてもらうと、原因はスリープ防止そのものでした。

調べ方は powercfg /requests です。いまスリープを止めているプロセスが一覧で出ます。管理者権限が要るので、ここだけは自分で管理者のターミナルを開いて実行し、結果を Claude に貼りました。

出てきたのは、3日前から動き続けている keep_awake.py でした。ある日、Claude がビルドを待つ間に、PID を渡さずに単体で起動していたのです。当時の版は PID がなければ永遠に回り続ける作りだったので、ビルドが終わっても止まりませんでした。

このプロセスを止めたら、自動スリープは元に戻りました。教訓は2つです。

  • スリープ防止は 必ず終わる条件とセットで起動する(PID を省略できる作りにしていたのが失敗のもと)
  • 「最近スリープしないな」と思ったら、まず powercfg /requests

2. 終わったら PC をスリープさせる

もう1つは逆向きです。寝る前に「終わったらスリープしておいて」と頼むと、作業が終わったところで Claude が PC をスリープさせてくれます。

実例1:デプロイが終わったらスリープ

夜中の2時半ごろ、「寝るので終わったら自動スリープしておいてほしい」と頼みました。Claude は次の順で進めて、約30分後に PC をスリープさせていました。

  1. スリープ用のスクリプトを先に用意する
  2. 3つのサービスを順にデプロイし、本番で動くことを確かめる
  3. スクリプトを実行してスリープ

スリープ用のスクリプトはこれです。休止状態ではなくスリープにしています。

Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.Application]::SetSuspendState([System.Windows.Forms.PowerState]::Suspend, $false, $false) | Out-Null

powershell -NoProfile -ExecutionPolicy Bypass -File sleep_pc.ps1 で実行しています。PowerShell 7(pwsh)では上の表のとおり System.Windows.Forms で失敗したことがあるので、Windows 標準の powershell(5.1)で動かしています。

実例2:記事を push したらスリープ

このサイトの記事を書き終えたあと、「書き終わったら数秒待ってスリープして」と頼みました。Claude は commit と push を済ませてから、次のコマンドを実行しました。

sleep 5; rundll32.exe powrprof.dll,SetSuspendState 0,1,0

翌日の夜に PC を起こすと、Claude の画面には 「2分でタイムアウトした」 と出ていました。Claude 自身も「スリープ中に時間切れになったのか、眠れなかったのか見分けがつかない」と言っています。

確かめる方法は Windows のイベントログです。Claude に Kernel-Power のログを読んでもらいました。

Get-WinEvent -FilterHashtable @{LogName='System'; ProviderName='Microsoft-Windows-Kernel-Power','Microsoft-Windows-Power-Troubleshooter'; StartTime=(Get-Date).AddHours(-12)} -MaxEvents 6 | Select-Object TimeCreated,Id,Message

結果は「03:04 にスリープし、20:03 に復帰」でした。スリープはちゃんと効いていて、タイムアウトは コマンドが返ってこないまま PC が眠ったので、起きたときに時間切れになっただけ でした。スリープさせるコマンドは、成功すると結果を返せないのが普通です。

なお、rundll32 で SetSuspendState を呼ぶ方法は、休止状態(ハイバネーション)が有効な PC ではスリープではなく休止状態になる、と言われています。確実にスリープさせたいなら、実例1の PowerShell の方法のほうが引数の意味がはっきりしています。

どこまで任せるか

スリープは取り消しの効かない操作ではありませんが、眠ったあとは Claude も何もできません。頼むときは次のことを意識しています。

  • 大事なものは先に外に出す。push・デプロイ・保存を済ませてからスリープ、の順番を頼むときに明示する
  • ほかに動いているものを確かめる。バックグラウンドの生成や、別のセッションの作業が残っていないか
  • スリープ防止とスリープ実行を同時に頼まない。スリープ防止が残っていても、明示的なスリープは効きます。ただ、ジョブを止めたくないから防止しているはずなので、両方を頼むときはジョブの完了を待ってから眠らせるように頼む
  • 結果は翌朝に確かめる。「タイムアウト」と出ていてもあわてず、イベントログで眠った時刻を見る

「寝る前に頼んで、朝に結果を見る」ができるようになって、長いジョブを回すのがずいぶん気楽になりました。

参考文献

この記事をシェア

「Windows」の記事(5件)

  1. ▶ PC のスリープを Claude Code に任せる(長いジョブの間は止めて、終わったら眠らせる)
  2. npm 版の Claude Code は更新が遅いと思って移行したら、原因は自分の設定だった
  3. 個人開発の Windows アプリを Microsoft Store に出すまで(MSIX パッケージ・wapproj のハマりどころ・審査メモ)
  4. Windows で Claude Code を使うときのハマりどころ(Git Bash・ヒアドキュメント・CRLF・子プロセス)
  5. Claude Code の statusLine が表示されない原因は PowerShell の起動遅延

関連する記事

Alexa-hosted スキルのビルドが jest で落ちた件と、ログを直接読めない環境でエラーを集計する方法

Alexa スキル「安眠ノイズ」に Jest のテストを足したら、Alexa-hosted のビルドが失敗するようになりました。原因の切り分けと、テストを lambda/ の外に出した構成、さらに CloudWatch Logs に直接アクセスできない Alexa-hosted で、エラーを Logs Insights で集計できる1行ログにした話をまとめます。

コード進行アプリの楽譜表示を自作した(大譜表・コード名どおりの綴り・転調で調号を変える)

コード進行生成アプリ Chord Eureka の楽譜表示を、html-midi-player(Magenta)の表示から、SVG を直接組み立てる自作の大譜表に置き換えました。E♭m がシャープで書かれる、進行によって音部記号が変わるといった問題をどう直したかと、置き換えるかどうかの判断をまとめます。

コード進行アプリにボイシングのプリセットを10種類足した(Drop 2・シェル・4度堆積など。既定の音は1バイトも変えない)

コード進行生成アプリ Chord Eureka に、Drop 2・シェル・ルートレス・4度堆積などのボイシングを選べる機能を足しました。既定の音を変えて一度戻した経緯、「書かれていない音は足さない」という決まり、各プリセットの組み立て方をまとめます。

Claude に「敵対的レビュー」をさせて、指摘がどれくらい当たっていたかを数えた

個人開発では、Claude Code に「壊れるところを探して」と頼む敵対的レビューを何度も使っています。4つのリポジトリに残っていた再検証の記録から、指摘がどれくらい当たり、どう外れていたかを数えました。外れ方には決まった型がありました。

テーマから探す