anthropics / anthropics/claude-plugins-official

Bug: Telegram plugin orphan process leak - server.ts not cleaned up on session end

オープン
#3,335 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る
主要言語
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

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。