原文(日本語訳)
セッション終了後にプロセスがハングする問題を修正しました。
原文(英語)
Fixed process hanging after session close
概要
Claude Code 2.1.39では、セッションを終了した後もClaude Codeのプロセスが終了せずにハングし続ける問題が修正されました。この修正により、リソースの適切な解放とクリーンなプロセス終了が保証され、システムリソースの無駄な消費が防止されます。
発生していた問題
症状
- セッション終了(
/exit、Ctrl+D、quit)後もプロセスが残留 - ターミナルを閉じてもバックグラウンドプロセスが動作し続ける
- 複数のゾンビプロセスが蓄積
- システムリソース(メモリ、ファイルディスクリプタ)のリーク
影響
bash
# 修正前: セッション終了後もプロセスが残る
claude
# ... セッションを終了
/exit
# ターミナルは終了するが、プロセスは残る
ps aux | grep claude
# user 12345 0.5 2.3 1234567 234567 ? S 10:00 0:15 claude
# user 12346 0.3 1.8 1234567 234567 ? S 10:05 0:10 claude
# user 12347 0.4 2.1 1234567 234567 ? S 10:10 0:12 claude実践例
正常な終了プロセス(修正後)
bash
# Claude Codeを起動
claude
# 作業を実施
# "Refactor the authentication module"
# セッションを終了
/exit
# 確認: プロセスが完全に終了している
ps aux | grep claude
# (何も表示されない)
echo $?
# 0(正常終了)Ctrl+Dでの終了
bash
claude
# Ctrl+D を押す
^D
# プロセスが即座に終了
# Goodbye! Session ended.
ps aux | grep claude
# (プロセスなし)シグナルによる終了
bash
# Claude Code実行中の別ターミナルから
# プロセスIDを取得
PID=$(pgrep -f claude)
# SIGTERMシグナルを送信
kill -TERM $PID
# 修正前: プロセスがハング
# 修正後: グレースフルシャットダウン
# Received SIGTERM. Saving session and exiting...
# Session saved to: ~/.claude/sessions/auto-save-12345.json
# Goodbye!
# プロセスが完全に終了
ps -p $PID
# (プロセスが見つからない)強制終了が必要なケース
bash
# 応答しないセッションの強制終了
# 修正前: SIGKILL が必要だった
kill -9 $PID
# 修正後: SIGTERM で十分
kill -TERM $PID
# または
claude --kill-all # すべてのClaude Codeプロセスを安全に終了リソース管理の改善
メモリリークの防止
bash
# 長時間セッション後の終了
# 修正前:
# - メモリが解放されない
# - スワップが発生
# - システムが重くなる
# 修正後:
# - すべてのリソースが適切に解放
# - メモリ使用量が即座に低下ファイルディスクリプタのクリーンアップ
bash
# 開いているファイルディスクリプタの確認
lsof -p $(pgrep claude)
# 修正前(終了後):
# claude 12345 user 10r REG /tmp/session.lock
# claude 12345 user 11w FIFO pipe
# claude 12345 user 12r DIR /home/user/project
# (ファイルが開いたまま)
# 修正後(終了後):
# (すべてのファイルが閉じられる)ネットワーク接続のクローズ
bash
# アクティブな接続の確認
netstat -anp | grep claude
# 修正前(終了後):
# tcp 0 0 127.0.0.1:54321 52.85.161.44:443 ESTABLISHED 12345/claude
# (接続が残る)
# 修正後(終了後):
# (すべての接続がクローズ)バックグラウンドタスクの処理
Agent Teams利用時
bash
# Agent Teamsを使用したセッション
export CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1
claude
# "Create a team of 5 agents for parallel refactoring"
# 修正前の終了:
# - メインセッションは終了
# - バックグラウンドのエージェントプロセスが残る
# 修正後の終了:
/exit
# Shutting down 5 agent team members...
# Agent 1: Saved and exited
# Agent 2: Saved and exited
# Agent 3: Saved and exited
# Agent 4: Saved and exited
# Agent 5: Saved and exited
# All agents terminated successfully
# Goodbye!MCPサーバーの切断
bash
# MCP接続を使用したセッション
claude mcp add puppeteer
claude
# MCPツールを使用した作業
/exit
# 修正後:
# Disconnecting from MCP servers...
# ✓ puppeteer server disconnected
# All MCP connections closed
# Goodbye!自動クリーンアップスクリプト
システムサービスとして実行する場合
bash
# systemd サービスファイル
# /etc/systemd/system/claude-code-cleanup.service
[Unit]
Description=Claude Code Cleanup Service
After=network.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/claude-cleanup.sh
[Install]
WantedBy=multi-user.targetbash
#!/bin/bash
# /usr/local/bin/claude-cleanup.sh
# 孤立したClaude Codeプロセスをクリーンアップ
ORPHANED=$(ps aux | grep -E 'claude.*--session' | grep -v grep | awk '{print $2}')
if [ -n "$ORPHANED" ]; then
echo "Cleaning up orphaned processes: $ORPHANED"
kill -TERM $ORPHANED
sleep 5
# まだ残っている場合は強制終了
REMAINING=$(ps aux | grep -E 'claude.*--session' | grep -v grep | awk '{print $2}')
if [ -n "$REMAINING" ]; then
kill -9 $REMAINING
fi
fiCron ジョブでの定期クリーンアップ
bash
# crontab -e
# 1時間ごとに孤立プロセスをチェック
0 * * * * /usr/local/bin/claude-cleanup.shモニタリングとアラート
プロセス監視スクリプト
python
#!/usr/bin/env python3
# monitor-claude-processes.py
import psutil
import time
from datetime import datetime
THRESHOLD_MINUTES = 60
def check_zombie_processes():
for proc in psutil.process_iter(['pid', 'name', 'create_time', 'status']):
try:
if 'claude' in proc.info['name'].lower():
runtime = time.time() - proc.info['create_time']
runtime_minutes = runtime / 60
if proc.info['status'] == psutil.STATUS_ZOMBIE:
print(f"WARNING: Zombie process detected!")
print(f" PID: {proc.info['pid']}")
print(f" Runtime: {runtime_minutes:.1f} minutes")
elif runtime_minutes > THRESHOLD_MINUTES:
print(f"INFO: Long-running process")
print(f" PID: {proc.info['pid']}")
print(f" Runtime: {runtime_minutes:.1f} minutes")
except (psutil.NoSuchProcess, psutil.AccessDenied):
pass
if __name__ == "__main__":
check_zombie_processes()注意点
- グレースフル シャットダウン: 強制終了(SIGKILL)ではなく、通常の終了(SIGTERM)を使用することで、セッションが保存されます
- 保存されていない作業: 終了前に作業が自動保存されますが、重要な変更は明示的にコミットすることをお勧めします
- 長時間実行タスク: バックグラウンドで長時間実行されるタスクがある場合は、完了を待つか、明示的にキャンセルしてください
- リソース制限: システムのリソース制限(ulimit)が適切に設定されていることを確認してください
トラブルシューティング
ハングしたプロセスの特定
bash
# Claude Codeプロセスの状態確認
ps aux | grep claude | grep -v grep
# プロセスのスレッド状態確認
ps -eLf | grep claude
# スタックトレースの取得
sudo gdb -p <PID>
(gdb) thread apply all bt
(gdb) quit強制終了が必要な場合
bash
# すべてのClaude Codeプロセスを強制終了
pkill -9 -f claude
# 特定のセッションのみ終了
kill -9 $(pgrep -f "claude.*--session-id=abc123")ログの確認
bash
# 終了ログの確認
tail -f ~/.claude/logs/shutdown.log
# 異常終了のログ
grep "abnormal" ~/.claude/logs/shutdown.log
grep "hang" ~/.claude/logs/shutdown.log