# Playwright 좀비 Chrome 프로세스 근본 해결

## 작업 레벨: Lv.4

## 배경
팀 봇이 E2E/스모크테스트 시 Playwright MCP로 Chrome을 띄우는데, 테스트 완료 후 browser_close를 호출하지 않아 좀비 프로세스가 남음. renderer 프로세스가 CPU 150~220%를 점유하며 서버 CPU가 98%까지 치솟는 장애가 **반복 발생** 중 (2026-04-29, 2026-04-30 최소 2회).

## 현재 상태 (문제 원인 4가지)

### 원인 1: finish-task.sh에 Chrome 정리 없음
- 파일: `/home/jay/workspace/finish-task.sh`
- QC, 머지, .done 생성만 수행. Playwright Chrome 프로세스 정리 로직 **전무**
- `pkill -f "python server.py"` 는 있으나 Chrome 은 없음

### 원인 2: DIRECT-WORKFLOW.md에 browser_close 의무화 없음
- 파일: `/home/jay/workspace/prompts/DIRECT-WORKFLOW.md`
- Step 4.8 "L1 스모크테스트"에서 Playwright 스크린샷만 요구, 정리 지시 없음
- 팀원이 browser_close() 호출을 빼먹어도 캐치 불가

### 원인 3: 자동 정리 크론/데몬 없음
- 좀비 Chrome이 장시간 누적되어도 자동 정리 메커니즘 부재
- 수동 `pkill`만 가능

### 원인 4: MCP 레이어에 타임아웃 없음
- playwright-mcp 래퍼(`/home/jay/workspace/mcp/playwright-mcp/`)에 자동 정리 설정 없음

## 수정 사항

### 1. finish-task.sh에 Chrome 정리 추가 (필수)

finish-task.sh의 작업 완료 단계(머지 후, .done 생성 전)에 자기 팀이 띄운 Playwright Chrome 프로세스를 정리하는 로직 추가:

```bash
# Playwright Chrome 좀비 정리
echo "[cleanup] Playwright Chrome 프로세스 정리..."
pkill -f "ms-playwright.*chromium.*chrome" 2>/dev/null || true
pkill -f "chrome-headless-shell" 2>/dev/null || true
sleep 1
# 강제 kill (SIGKILL)
pkill -9 -f "ms-playwright.*chromium.*chrome" 2>/dev/null || true
pkill -9 -f "chrome-headless-shell" 2>/dev/null || true
echo "[cleanup] Playwright Chrome 정리 완료"
```

★ 주의: 다른 팀이 동시에 E2E 중일 수 있으므로, 가능하면 자기 세션(user-data-dir)에 해당하는 프로세스만 kill하는 방식을 검토할 것. 불가능하면 전체 kill도 허용 (Playwright는 필요 시 재생성하므로).

### 2. DIRECT-WORKFLOW.md에 browser_close 의무화 (필수)

Step 4.8 "L1 스모크테스트" 섹션에 아래 지시 추가:

```markdown
### ★ Playwright 브라우저 정리 (필수)
E2E/스모크테스트 완료 후 반드시 `browser_close` 도구를 호출하여 브라우저를 닫으세요.
미정리 시 Chrome renderer가 CPU 100%+ 좀비로 남아 서버 장애를 유발합니다.

체크리스트:
- [ ] 스크린샷 캡처 완료
- [ ] browser_close 호출 완료
- [ ] ps aux | grep chrome 으로 잔존 프로세스 없음 확인
```

### 3. 좀비 Chrome 자동 정리 크론 스크립트 (필수)

파일: `/home/jay/workspace/scripts/cleanup-zombie-chrome.sh`

```bash
#!/bin/bash
# 30분 이상 실행 중인 Playwright Chrome 프로세스 자동 kill
# CPU 100% 이상 점유하는 renderer 프로세스 즉시 kill

# 1. CPU 100% 이상 Playwright Chrome renderer 즉시 kill
ps aux | grep 'ms-playwright.*chrome.*type=renderer' | grep -v grep | awk '{if ($3 > 100) print $2}' | xargs -r kill -9

# 2. CPU 100% 이상 chrome-headless-shell renderer 즉시 kill
ps aux | grep 'chrome-headless-shell.*type=renderer' | grep -v grep | awk '{if ($3 > 100) print $2}' | xargs -r kill -9

# 3. 60분 이상 실행 중인 Playwright Chrome 전체 kill (정상 E2E는 10분 내 완료)
find /proc -maxdepth 1 -name '[0-9]*' -type d 2>/dev/null | while read pid_dir; do
    pid=$(basename "$pid_dir")
    cmdline=$(cat "$pid_dir/cmdline" 2>/dev/null | tr '\0' ' ')
    if echo "$cmdline" | grep -q 'ms-playwright.*chrome\|chrome-headless-shell'; then
        # 프로세스 시작 시간 확인 (분 단위)
        elapsed=$(ps -o etimes= -p "$pid" 2>/dev/null | tr -d ' ')
        if [ -n "$elapsed" ] && [ "$elapsed" -gt 3600 ]; then
            echo "[$(date)] Killing zombie Chrome PID=$pid (elapsed=${elapsed}s)"
            kill -9 "$pid" 2>/dev/null
        fi
    fi
done

# 4. playwright-mcp의 user-data-dir 임시 파일 정리 (디스크 누수 방지)
find /tmp -maxdepth 1 -name 'playwright_chromium*' -mmin +60 -exec rm -rf {} + 2>/dev/null
find /home/jay/.cache/ms-playwright -maxdepth 1 -name 'mcp-chrome-*' -mmin +60 -exec rm -rf {} + 2>/dev/null
```

### 4. systemd timer 등록 (또는 crontab)

```bash
# 5분마다 실행
*/5 * * * * /home/jay/workspace/scripts/cleanup-zombie-chrome.sh >> /tmp/cleanup-zombie-chrome.log 2>&1
```

또는 systemd timer 방식:

파일: `/home/jay/.config/systemd/user/cleanup-zombie-chrome.service`
```ini
[Unit]
Description=Cleanup zombie Playwright Chrome processes

[Service]
Type=oneshot
ExecStart=/home/jay/workspace/scripts/cleanup-zombie-chrome.sh
```

파일: `/home/jay/.config/systemd/user/cleanup-zombie-chrome.timer`
```ini
[Unit]
Description=Run cleanup-zombie-chrome every 5 minutes

[Timer]
OnBootSec=2min
OnUnitActiveSec=5min

[Install]
WantedBy=timers.target
```

```bash
systemctl --user daemon-reload
systemctl --user enable --now cleanup-zombie-chrome.timer
```

### 5. Telegram 알림 연동 (선택, 권장)

좀비 kill 발생 시 Telegram으로 알림:
```bash
if [ -n "$KILLED_PIDS" ]; then
    "/usr/local/bin/cokacdir" --sendmsg "⚠️ 좀비 Chrome ${count}개 자동 kill됨 (PIDs: ${KILLED_PIDS})" --chat 6937032012 --key c119085addb0f8b7
fi
```

## affected_files
- `/home/jay/workspace/finish-task.sh` (수정 — Chrome 정리 로직 추가)
- `/home/jay/workspace/prompts/DIRECT-WORKFLOW.md` (수정 — browser_close 의무화 추가)
- `/home/jay/workspace/scripts/cleanup-zombie-chrome.sh` (신규 — 자동 정리 스크립트)
- `/home/jay/.config/systemd/user/cleanup-zombie-chrome.service` (신규 — systemd 서비스)
- `/home/jay/.config/systemd/user/cleanup-zombie-chrome.timer` (신규 — systemd 타이머)

## 검증 시나리오
1. finish-task.sh 실행 후 Playwright Chrome 프로세스 0건 확인
2. DIRECT-WORKFLOW.md에 browser_close 의무화 지시 존재 확인
3. cleanup-zombie-chrome.sh 수동 실행 → CPU 100%+ renderer 정리 확인
4. systemd timer 상태 `systemctl --user status cleanup-zombie-chrome.timer` → active
5. 의도적으로 Playwright Chrome을 띄운 후 60분 경과 → 자동 kill 확인
6. CPU 100%+ renderer를 시뮬레이션(stress 등) → 5분 내 자동 kill 확인
7. kill 발생 시 Telegram 알림 수신 확인
8. 기존 finish-task.sh의 다른 기능(QC, 머지, .done 생성) 정상 동작 확인