본문 바로가기
C.W.K.
Stream
Lesson 02 of 04 · published

device turn ID

~12 min · idempotency-key, identity, dedupe, client-generated

Level 0신호 없음
0 XP0/32 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"dedupe 키는 첫 전송 전에 이미 있어야 해. 그 말은 서버가 아니라 클라이언트가 발급해야 한다는 거고."

왜 ID 가 폰에서 태어나나

재시도를 dedupe 하려면 같은 의도로 하는 시도가 전부 같은 키를 달고 있어야 해. 그럼 그 키가 처음 있어야 하는 시점이 언제일까? 캡처할 때야. 첫 전송 바로 전에. 그 첫 전송이 하필 확인을 못 받고, 그래서 제대로 된 키를 달고 다시 보내야 하는 상황을 만드는 놈일 수 있거든. 서버가 ID 를 발급하면 폰은 응답이 돌아오기 전까진 그걸 못 가져. 그런데 그 응답이 날아가 버리면 재시도할 때 맞춰 볼 키가 없는 거고. 그래서 device turn ID 는 폰에서, 캡처하는 시점에 발급되고, 첫 시도부터 모든 시도에 같이 따라다녀.

키 하나가 canonical 로그에도 남아

device turn ID 는 폰 쪽 사정만이 아냐. 그게 가리키는 턴이랑 나란히 canonical 로그에도 기록돼. 그게 이 키를 로컬 추측이 아니라 진짜 dedupe 키로 만들어. 백엔드가 갖고 있으니까, 이미 끝난 걸로 아는 ID 를 단 요청이 또 오면 반복인 걸 알아보고 일을 다시 하는 대신 있던 결과를 돌려줄 수 있거든. 이 키가 폰이랑 백엔드가 불안한 링크를 사이에 두고 '이거 같은 턴이야' 라고 합의하는 공용어야.

  • 발급. 기기에서, 캡처할 때, UUID 로. 아무하고도 상의 안 하고 전역에서 안 겹쳐.
  • 보관. 로컬 outbox 에, 그리고 턴이 도착하면 canonical 로그에도.
  • 운반. 그 의도로 하는 배달 시도랑 재시도 전부에, 값 하나 안 바뀐 채로.

안 바뀌는 정체성이 트릭 전부야

힘은 전부 그 ID 가 시도가 몇 번이든 안 바뀐다는 데서 나와. 재시도할 때마다 새 ID 를 만들면 목적이 통째로 깨져. 백엔드 눈엔 한 턴을 세 번 시도한 게 아니라 서로 다른 턴 세 개로 보이거든. 규칙은 빡빡해. 의도 하나에 ID 하나, 그 턴이 살아 있는 내내. 캡처할 때 한 번 발급하고, 바로 저장하고, 몇 번을 다시 보내든 새로 만들지 않기. 다음 레슨들이 하는 일이 전부 여기 기대고 있어. 부르기 전에 확인하기, 더블 전송 피하기. 다 이 식별자 하나가 안 변한다는 전제 위에 서 있는 거야.

Code

캡처할 때 한 번 발급, 모든 시도에 그대로 운반·typescript
// 캡처 때 — 어떤 네트워크 시도 전에도 — 안정된 키를 발급.
function createTurn(question: string, attachmentIds: string[]): PippaGoTurn {
  return {
    deviceTurnId: crypto.randomUUID(), // 기기에서, 한 번, 캡처 때
    question,
    attachmentIds,
    syncStatus: "pending",
  };
}

// 모든 배달 시도가 같은 id 를 보냄. 재시도는 재사용하지 새로 발급 안 함.
async function deliver(turn: PippaGoTurn) {
  return callCanonical({ ...turn, idempotencyKey: turn.deviceTurnId });
}

// 틀림: deliver() 안에서 `idempotencyKey: crypto.randomUUID()` —
// 시도마다 새 키는 세 재시도를 세 턴처럼 보이게 만들어.

External links

Exercise

턴 하나의 device turn ID 를 따라가 봐. 캡처, 첫 전송(ack 유실), 재시도, 백엔드가 알아보는 순간까지. 단계마다 ID 값을 적고 한 번도 안 바뀌는지 확인해. 그다음 일부러 깨 봐. 재시도할 때 ID 를 새로 만드는 거야. 그러면 백엔드 눈에 뭐가 보이는지, 왜 사용자가 두 번 청구되거나 답을 두 번 받을 수 있는지 정확하게 적어.
Hint
ID 가 안 바뀌면 백엔드는 두 번째 요청을 보고 '아 turn X 또 왔네, 이미 했어, 답 여깄어' 해. ID 를 새로 만들면 '완전 새로운 turn Y 네' 하면서 일을 다시 하고. 코드 경로는 같은데 결과는 정반대야. 갈리는 지점은 오직 키가 그대로였느냐 하나고.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.