"claim 이 건드린 건 뭐든, reclaim 이 되돌려야 해 — 전부, atomic 하게."
heartbeat 가 멈춘다
worker 가 전사 중에 죽어: 정전, 크래시, 누가 기계를 재시작. heartbeat 가 멈춰. lease 가 다 돼. 이제 control plane 이 치워야 하고, 여기가 미묘하고 잔인한 버그가 사는 곳이야.
뻔한 정리는: lease 만료 → job 을 queued 로 되돌려 다른 worker 가 claim 하게. Recall 은 정확히 그렇게 하고, 새 claim 이 허락되기 전에 해서, stale lease 가 절대 이중 claim 안 되게. 근데 'job 을 queued 로 되돌리기' 는 이야기의 절반일 뿐이고, 빠진 절반이 무는 놈이야.
claim 이 둘을 건드렸으니, reclaim 도 그래야 해
claim 이 뭘 했는지 기억해: job 을 queued 에서 leased 로 옮겼고, 그리고 그 job 의 batch item 을 queued 에서 transcribing 으로 옮겼어. 두 행이 바뀌었어. 그래서 reclaim 이 job 만 리셋하면, batch item 은 영영 'transcribing' 이라 말하며 남아 — 아무도 전사 안 하는데. queue 는 기술적으로 맞고(job 이 돌아왔고, 다른 worker 가 가져감) batch 의 진행 뷰는 영구히 거짓말해: 영원히 진행 중인 item, 허구에서 계산된 ETA, 살아 있어 보이는데 아닌 batch 를 노려보는 operator.
그래서 Recall 의 reclaim 은 job 이랑 그 batch item 을 둘 다 queued 로 atomic 하게 되돌려 — 트랜잭션 하나, 두 행, 전부 아니면 전무. 그 단어가 중요해: 한 행을 리셋하고 다른 것 전에 크래시하는 reclaim 은 자기가 치우던 바로 그 orphan 을 다시 만들어. 일반 규칙은 대칭이야: claim 이 변형하는 상태는 뭐든, reclaim 이 단일 atomic 단계로 복원해야 해. 부분 reclaim 은 더 작은 고침이 아냐 — 정리의 옷을 입은 새 불일치야.
그리고 틈새로 크래시한 걸 치유해
atomic reclaim 이 있어도 틈 하나가 남아: 'job 완료' 와 'batch item 갱신' 사이 좁은 창에 떨어지는 크래시. job 은 진짜 끝났는데, 그 item 은 여전히 transcribing 으로 읽혀 — 그리고 그걸 고칠 lease 만료가 없어, job 이 더는 leased 가 아니니까. 그래서 Recall 은 두 번째 안전망을 더해: 시작 시랑 job claim 시, reconcile 해 — batch item 이 중간에 남은 완료 job 을 찾아 수리해. 이게 reconciliation-loop 본능이야: 모든 전이가 완벽히 짝지어졌다고 믿는 대신, 주기적으로 현실을 기록이 주장하는 것과 비교하고 차이를 치유해. lease 는 예상한 크래시를 다루고; reconciliation 은 예상 못 한 크래시 창을 다뤄.