C.W.K.
Stream
Lesson 03 of 05 · published

ambiguous 상태

~12 min · ambiguous, state-machine, billing, uncertainty

Level 0Empty Shelf
0 XP0/35 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"'결제했을지도 모르는데 손에 아무것도 없다' 는 진짜 상태야. 이름을 줘."

대부분의 시스템이 모델링을 거부하는 상태

유료 제출은 작은 상태 기계를 지나: preparingsubmittingcompleted. 깔끔해 보여. 근데 대부분의 설계가 없는 척하는 갈림길이 있고, 그게 돈이 드는 놈이야. executor 가 submitting 에 있다고 그려봐: 요청을 보냈고, 그다음 응답이 오기 전에 연결이 죽었어. 지금 상태가 뭐야?

진짜 몰라. provider 가 요청을 받고, 전사를 돌리고, 청구했을 수 있어 — 응답만 집에 못 온 거고. 아니면 요청이 아예 도착 안 했을 수도. Recall 이 선 자리에서 그 두 세계는 구별 불가능하고, 정반대의 재정적 결과를 가져. 성공인 척하면 결과를 잃고; 깔끔한 실패인 척하면 이중 청구할 수 있는 재시도를 불러. 정직한 답은: 이건 세 번째 것이고, 자기 이름이 필요해.

추측하지 말고 이름 지어

Recall 은 그걸 ambiguous 라 부르고, 해결될 때까지 terminal 인 진짜 상태로 모델링해. 규칙이 정확해:

  • completed 는 새 호출 없이 저장된 응답을 돌려줘 — 안전한, 이미 결제된 경로.
  • executor 의 outbox 에 저장된 provider 응답이 있는 submitting그 저장된 응답에서 완료돼(다음 레슨) — 새 청구 없음.
  • 저장된 응답이 없는 submittingambiguous: 청구됐을지도, 아닐지도, 손에 결과 없음.

그리고 결정적 규칙: ambiguous 호출은 절대 자동 재시도 안 해. blind 재시도는 진짜 돈을 건 동전 던지기야 — 앞면이면 필요했고, 뒷면이면 방금 두 번 결제. 그래서 Recall 은 멈추고 불확실성을 사람에게 보내. 사람이 provider 의 실제 청구 기록을 확인하고, 두 세계 중 어느 게 진짜인지 배우고, 호출을 명시적으로 해결해: 청구 안 됨(다시 해도 안전), 청구됐지만 잃음(손실 인정, 공짜로 다시 안 함), 아니면 청구됐고 진짜 다시 결제해야 함(별도의 명시적 승인). 기계는 추측이 돈을 쓰는 데선 추측을 거부해.

왜 일급 상태가 최선의 추측을 이겨

유혹은 늘 코드 분기를 줄이려고 모호함을 성공이나 실패로 무너뜨리는 거야. 그 깔끔함이 정확히 버그야. '아마 실패, 재시도' 로 접은 불확실성은 조용히 이중 지출을 승인하고; '아마 괜찮음' 으로 접은 불확실성은 조용히 데이터를 잃어. ambiguous 상태를 자기 이름 가진 것으로 모델링 — 주차됨, 재시도 안 됨, 기계엔 없는 ground truth(provider 청구) 접근권 가진 사람을 기다림 — 하는 게 돈을 정직하게 유지해. 기계가 알 수 없을 때, 맞는 수는 자신만만한 추측이 아냐; 사람이 해결할 수 있는 명시적 '난 몰라' 야.

Code

유료 제출 상태 기계 (갈림길이 핵심)·text
preparing ──▶ submitting ──▶ completed
                   │
                   └──▶ ambiguous   (제출됨, 응답 없음,
                                      저장된 outbox 사본 없음)

completed  : 저장된 응답 반환, 새 POST 없음
submitting + outbox 응답 : 저장된 사본에서 완료
submitting + 응답 없음   : AMBIGUOUS  (청구됐나?)

ambiguous 는 절대 자동 재시도 안 함. 사람이 청구를 조사한 뒤:
  resolve --not-billed     -> 다시 해도 안전
  resolve --billed-lost    -> 손실 인정, 공짜로 다시 안 함
  resolve --billed-lost --allow-paid-rerun -> 명시적 재결제

External links

Exercise

네 일에서 부작용 후, 부작용이 일어났는지 알 수 없는 방식으로 실패할 수 있는 작업을 찾아 — timeout 난 결제, 확인 안 된 메시지 전송, 착지했을지도 모르는 write. 지금 그 경우 네 코드는 뭘 해: 성공 가정, 실패 가정, 재시도? 거기다 명시적 'ambiguous' 상태를 설계해: 뭐가 주차되고, 사람이 어떤 ground truth 를 확인하고, 해결 선택지가 뭐야.
Hint
신호는 '보낸 뒤 timeout' 을 '보낸 적 없음' 과 같게 다루는 catch 블록이야. 그건 다른 비용의 다른 상태야. '알 수 없음 — 재시도 마' 를 뜻하는 세 번째 결과를 더하고, 나중에 조사할 만큼 기록하고, 명시적 사람 해결(일어남/안 일어남/일부러 재실행) 을 정의해. 목표는 기계가 추측으로 쓰거나 파괴하게 절대 안 두는 거야.

Progress

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

댓글 0

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

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