"안전한 재시도는 '다시 보낼까?' 를 묻지 않아. '이 턴한테 이미 무슨 일이 있었지?' 를 묻지. 그리고 답은 꽤 자주 '더 할 거 없음' 이야."
재시도는 재전송이 아니라 질문이야
순진한 재시도는 그냥 요청을 다시 쏴. 안전한 재시도는 device turn ID 로 턴 상태부터 확인하고, 호출할 명분이 진짜 있을 때만 모델을 불러. 배달이 적어도 한 번이니까, 재시도가 사실은 이미 멀쩡히 성공한 걸 또 보내는 걸 수도 있거든. 답은 있고 확인만 못 받은 거지. 무작정 다시 보내면 진짜 일을 한 번 더 하게 되고. 그래서 모델을 부르기 전에 클라이언트는 턴을 세 상태 중 하나로 확정해.
- 완료. 백엔드가 이 device turn ID 에 대한 답을 이미 갖고 있어. 모델 부르지 말고 그 답을 가져다 보여줘.
- 대기. 턴은 알고 있고 처리 중이거나 큐에 있는데 아직 답이 안 나왔어. 다시 부르지 말고 기다려서 결판나게 둬.
- 모름. 백엔드에 이 ID 기록이 아예 없어. 모델을 불러도 되는 유일한 상태야. 그 의도가 진짜로 실행이 안 된 거니까.
가드가 중복을 no-op 으로 바꿔
이 확인이 정확히 한 번 의도를 실제로 만들어내는 장치야. 지난 레슨의 dedupe 키가 안 바뀌는 정체성을 주고, 이 가드가 그걸 쓰는 거지. 재시도는 전부 같은 게이트를 지나. 상태를 확정하고, 그다음에 갈라져. 완료랑 대기는 둘 다 새 일 없이 거기서 끊겨. 적어도 한 번 배달을 무해하게 만들어 주는 no-op 이지. 모름일 때만 모델까지 가고. 이 가드가 클라이언트 쪽에서 중복을 다 흡수하니까 선 위에서 중복을 막을 필요가 없어.
확인이 어디 있느냐가 중요해
가드는 모델 호출 뒤가 아니라 앞에 둬. 모델 부르고 나서 도는 확인은 아끼려던 비용을 이미 다 쓴 뒤야. 맞는 모양은 이래. 재시도할 때 ID 로 턴 상태를 백엔드한테 물어봐. 아니면 거기서 동기화돼 온 로컬 기록을 읽든가. 그 답에 따라 갈라지고. 모름 쪽으로 갈렸을 때만 모델을 불러. 몇 줄 안 되는데, 그 몇 줄이 안전하게 재시도하는 클라이언트랑 소리 없이 모든 걸 두 번 하는 클라이언트를 가르는 전부야.