Skip to content

fix(supervise): cleanStaleLocks removes stale postmaster.pid (container PID-recycling CrashLoop)#276

Merged
KeiaiLab-PHIL merged 1 commit into
mainfrom
fix/postmaster-pid-race-container-pid-recycling
Jun 22, 2026
Merged

fix(supervise): cleanStaleLocks removes stale postmaster.pid (container PID-recycling CrashLoop)#276
KeiaiLab-PHIL merged 1 commit into
mainfrom
fix/postmaster-pid-race-container-pid-recycling

Conversation

@KeiaiLab-PHIL

Copy link
Copy Markdown
Contributor

Root cause (postgres-prod 7-day CrashLoopBackOff)

supervise.gocleanStaleSocket()는 unix socket lock만 정리하고 DataDir의 postmaster.pid"PostgreSQL 자체가 PID-alive 검사 후 stale 처리" 한다고 가정했다. 이 가정이 컨테이너 PID 재활용 환경에서 거짓:

  1. 컨테이너 PID 재활용으로 postgres가 매 기동 동일 PID(예: 15)를 얻음
  2. 직전 crash가 남긴 postmaster.pid의 PID(15)를 PostgreSQL kill(pid,0) liveness 검사가 *"살아있음"*으로 오인 → FATAL: lock file "postmaster.pid" already exists
  3. init 컨테이너의 1회성 pid 정리는 **메인 컨테이너 재시작(CrashLoopBackOff 시 init 미재실행)**을 못 막음 → 최초 1회 crash 후 잔존 pid가 모든 후속 재시작을 영구 차단

라이브 trigger: 리더 역할 전환 시 supervisor의 postgres 재시작이 첫 crash를 유발 → 이후 무한 루프.

Fix

cleanStaleSocketcleanStaleLocks 확장: socket lock과 동일 안전 논리(Start()의 fork 직전 = pod 내 live postmaster 부재 + 각 shard 전용 RWO PVC = cross-pod 데이터 dir 공유 없음)로 DataDir postmaster.pid도 매 Start() 제거. init 1회성이 아닌 매 재시작 커버 → 루프 차단.

Tests

  • go test ./internal/instance/supervise/... ok (회귀 0)
  • 신규 회귀 가드: TestReal_cleanStaleLocks_RemovesPostmasterPid + TestReal_cleanStaleLocks_NoPidIsNoError PASS

Live verification (postgres-prod, 2026-06-22)

ghcr.io/keiailab/pg:18-pidfix (linux/amd64) 빌드 → ClusterImageCatalog keiailab-pg 갱신 → 전 샤드 재생성:

  • postgrescluster postgres-prod: Provisioning/False (7d) → Ready/True
  • shard-0-0 1/1 Running (0 restarts), SELECT 1 → 1, "database system is ready to accept connections"
  • postmaster.pid FATAL 재발 = 0

Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com

…용 CrashLoop RCA)

postgres-prod 7일 CrashLoopBackOff RCA: 컨테이너 PID 재활용으로 postgres 가 매 기동 동일 PID(15)를 얻어, 직전 crash 가 남긴 postmaster.pid 의 PID 를 PostgreSQL kill(pid,0) liveness 검사가 살아있음으로 오인 → FATAL lock file already exists 무한 fail. init 컨테이너 1회성 정리는 메인 컨테이너 재시작(CrashLoop 시 init 미재실행)을 못 막음.

cleanStaleSocket→cleanStaleLocks 확장: socket lock 과 동일 안전논리(Start fork 직전=pod 내 live postmaster 부재 + shard 전용 RWO PVC)로 DataDir postmaster.pid 도 매 Start 제거. 검증: go test supervise ok + 회귀가드 2 PASS.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@KeiaiLab-PHIL KeiaiLab-PHIL merged commit 8b96b2a into main Jun 22, 2026
@KeiaiLab-PHIL KeiaiLab-PHIL deleted the fix/postmaster-pid-race-container-pid-recycling branch June 22, 2026 21:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant