"안전한 재시도는 '다시 보낼까?'를 묻지 않아. '이 턴한테 이미 뭐가 일어났지?'를 물어 — 그리고 종종 답은 '더 할 거 없음'이야."
재시도는 재전송이 아니라 질문이다
순진한 재시도는 그냥 요청을 다시 쏴. 안전한 재시도는 먼저 device turn ID 로 키한 턴의 상태를 확인하고, 호출이 실제로 정당할 때만 모델을 불러. 배달이 적어도 한 번이니까, 재시도는 이미 완전히 성공한 걸 다시 보내는 걸 수도 있어 — 답이 존재하고, 확인만 잃었어. 맹목적으로 다시 보내면 진짜 작업을 다시 해. 그래서 어떤 모델 호출 전에도, 클라이언트는 턴을 세 상태 중 하나로 해소해:
- 완료 — 백엔드가 이 device turn ID 에 대한 답을 이미 가짐. 모델 부르지 마; 기존 답을 가져와 보여줘.
- 대기 — 턴이 알려졌고 진행 중이거나 큐에 있지만, 답 안 됨. 다시 부르지 마; 기다려서 해소되게 해.
- 모름 — 백엔드에 이 ID 기록이 없음. 모델 부르는 게 맞는 유일한 상태야: 의도가 진짜로 수행 안 됐어.
가드가 중복을 no-op 으로 바꾼다
이 확인이 정확히 한 번 의도를 배달하는 구체적 메커니즘이야. 지난 레슨의 dedupe 키가 안정된 정체성을 주고, 이 가드가 그걸 쓰는 거야. 모든 재시도가 같은 게이트를 지나: 상태 해소, 그다음 분기. 완료랑 대기 둘 다 새 작업 없이 short-circuit 해 — 적어도 한 번 배달을 무해하게 만드는 no-op 이야. '모름'만 모델로 나아가. 이 가드가 클라이언트에서 중복을 흡수하니까 선 위에서 중복을 막을 필요가 없어.
확인이 어디 사는지가 중요하다
가드를 모델 호출 뒤가 아니라 앞에 둬. 모델을 부른 뒤 도는 확인은 피하려던 비용을 이미 치렀어. 맞는 모양은: 재시도 때, ID 로 턴 상태를 백엔드한테 물어(또는 거기서 동기화된 내구성 있는 로컬 기록을 읽어); 답에 분기; 모름 분기에서만 모델을 불러. 몇 줄이지만, 그 줄들이 안전하게 재시도하는 클라이언트랑 조용히 모든 걸 두 번 하는 클라이언트의 차이 전부야.