anthropics / anthropics/claude-plugins-official
Bug: Telegram plugin orphan process leak - server.ts not cleaned up on session end
- 主要言語
- Python
- スター
- 36.3k
- フォーク
- 4.1k
- 平均マージ
- 2日 14時間
- マージ済み PR(30日)
- 539
説明
# Bug: Telegram plugin orphan process leak - server.ts not cleaned up on session end
## Description
The current orphan watchdog mechanism in the Telegram plugin has a flaw that causes `server.ts` processes to not be cleaned up when Claude Code sessions end, resulting in orphaned process leaks.
Each orphaned process continuously consumes ~99% CPU, and after multiple sessions, system load can reach 14+.
## Root Cause Analysis
**Process structure:**
```
claude(113449) → wrapper(113515) → server.ts(113536)
```
**Current monitoring code** (`server.ts:667-677`) only checks:
- Whether `process.ppid` has changed (direct parent)
- Whether stdin has been destroyed
**The problem:**
When `claude` dies:
1. `wrapper` gets reparented to systemd (PPID becomes 2221)
2. `server.ts`'s parent is still `wrapper` (PPID unchanged!)
3. `wrapper`'s stdin may still be open
4. None of the monitoring conditions are met → `server.ts` runs forever
**Evidence: 10 orphaned process pairs found:**
```
wrapper 128570 → systemd (2221)
wrapper 129251 → systemd (2221)
[... 10 total pairs]
```
Each `server.ts`'s parent is its corresponding `wrapper`, and the PPID never changed.
## Proposed Fix
**Solution 1: Check ancestor process** (implemented and tested)
- Walk up the process tree at startup to find the Claude ancestor PID
- Check every 5 seconds if the Claude ancestor is still alive
- If ancestor died → trigger `shutdown()`
Code attached below.
**Solution 2:** Wrapper signal forwarding
- Add signal forwarding logic in the `bun run` wrapper
**Solution 3:** Use process groups
- Create independent process group at startup, kill entire group on session end
## Environment
- **OS:** Ubuntu (Linux 7.0.0-15-generic)
- **Claude Code:** 2.1.187
- **Plugin:** telegram 0.0.6
- **Bun:** latest
## Steps to Reproduce
1. Start Claude Code session (with telegram plugin enabled)
2. Use normally for some time
3. Exit Claude Code gracefully (not kill -9)
4. Check processes: `ps aux | grep "telegram.*server.ts"`
5. Repeat steps 1-4 ten times
6. Observe: ~10 orphaned `server.ts` processes, each at ~99% CPU
## Expected Behavior
When Claude Code exits, the telegram `server.ts` should automatically clean up within 5 seconds.
## Actual Behavior
`server.ts` continues running, becomes an orphaned process, consuming 99% CPU until manually killed.
## Attachment - Fix Code (Solution 1)
```typescript
// Orphan watchdog: stdin events above don't reliably fire when the parent
// chain (`bun run` wrapper → shell → us) is severed by a crash. Poll for
// ancestor death (Claude process) or a dead stdin pipe and self-terminate.
// Helper: walk up the process tree to find the Claude ancestor
function findClaudeAncestor(): number | null {
try {
let currentPid = process.ppid
const maxDepth = 10
let depth = 0
while (currentPid > 1 && depth < maxDepth) {
try {
const stat = readFileSync(`/proc/${currentPid}/stat`, 'utf8')
const comm = stat.split(' ')[1].replace(/\(|\)/g, '')
const ppid = parseInt(stat.split(' ')[3], 10)
// Check if this is the Claude process
if (comm === 'claude' || stat.includes('claude --')) {
return currentPid
}
currentPid = ppid
depth++
} catch {
// Process died during check
break
}
}
return null
} catch {
return null
}
}
// Store Claude ancestor PID at startup
const claudeAncestorPid = findClaudeAncestor()
setInterval(() => {
const orphaned =
(process.platform !== 'win32' && claudeAncestorPid !== null && !claudeAncestorPidAlive()) ||
process.stdin.destroyed ||
process.stdin.readableEnded
if (orphaned) shutdown()
}, 5000).unref()
// Helper: check if Claude ancestor is still alive
function claudeAncestorPidAlive(): boolean {
if (claudeAncestorPid === null) return true // No Claude ancestor found, assume alive
try {
readFileSync(`/proc/${claudeAncestorPid}/stat`, 'utf8')
return true
} catch {
return false // Claude ancestor died
}
}
```
コントリビューションガイド
このリポジトリのコントリビューションガイドは索引されていません
調査の方向性
Inspect the Telegram plugin's server.ts watchdog around lines 667-677 and review the attached ancestor-process proposal. Reproduce the session-exit sequence on Linux, then verify that server.ts shuts down within five seconds and that repeated exits leave no orphaned high-CPU processes.
索引モデルが issue の本文から書いたものです。
評価
- 技術スタック
- bun, linux, typescript
- 領域
- backend, devtools, operating-systems
- issue の種類
- バグ
- 難易度
- 3/5
- 見積もり時間
- 1〜2日
- 活発さ
- 静か
- 明瞭さ
- おおむね明確
- 初心者へのやさしさ
- 58/100