"control plane 이 durably 받아들이기 전엔 계산이 안 끝나."
시스템에서 가장 중요한 한 문장
Recall 의 분산 설계 전부가 한 규칙으로 무너져. executor 는 transcript 계산을 끝낼 수 있어 — 함수가 return 했고, 파일이 디스크에 있고, 로그가 성공이래 — 근데 그 어느 것도 job 이 완료됐다는 뜻은 아냐. 완료는 일을 한 기계가 아니라 진실의 원천의 속성이야. job 은 control plane 이 결과를 받아들였다고 durably 기록했을 때, 오직 그때만 끝나.
왜 이렇게 엄격해? 'executor 가 끝냈다' 랑 'control plane 이 안다' 사이엔 네트워크가 있고, 네트워크는 실패하니까. executor 가 완벽한 결과를 계산하고 나서 보고하기 전에 연결을 잃을 수도 있어. 그걸 '완료' 라고 부르면, 진실이랑 일이 조용히 어긋나 — executor 는 끝났다고 생각하고, DB 는 job 이 아직 pending 이라고 생각해. 그 틈이 최악의 버그가 사는 곳이야.
끝내는 건 싸. 수락은 durable 해.
그래서 executor 의 로컬 '완료' 감각은 사실이 아니라 제안으로 다뤄. 결과를 계산하고, control plane 에 제출하고, control plane 이 검증한 다음 상태 전이를 한 번의 atomic DB write 로 커밋해. 그 커밋만이 완료야. return 한 함수는 소문이고, 커밋된 전이는 진실이야.
이게 전부를 버티게 만들어. executor 가 계산 후 보고 전에 죽이면 — control plane 이 수락을 본 적 없고, lease 가 만료되고, job 이 queue 로 돌아가고, 다시 돌아. control plane 이 커밋한 후에 죽이면 — job 은 진짜로 끝났고 다시 안 돌아. 중요한 단 하나의 순간은 durable 커밋이고, 그건 진실을 소유하는 호스트에 살아.
replay 는 안전해야 해
미묘한 게 있어: executor 가 계산하고, control plane 이 커밋했는데, executor 로 돌아가는 확인(ack)이 유실되면? executor 는 성공한 걸 몰라서 재시도하고 — 이제 같은 결과가 두 번 도착해. 시스템이 그걸 무해하게 만들어야 해. Recall 은 identity 로 해: 이미 받아들인 결과의 재제출은 중복을 만드는 대신 기존 record 를 돌려줘. 재시도는 항상 안전해, 수락이 idempotent 하니까. 거기 더해, control plane 이 재시작하면 크래시가 중간에 남긴 job 을 화해(reconcile) 시켜. '한 번 수락, 안전하게 replay, 시작 시 치유' 가 두 호스트가 불안정한 네트워크 너머로 정직하게 남는 방법이야.