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

끊김은 상태를 바꾸지 입력을 안 바꿔

~11 min · state-machine, immutability, resilience, status

Level 0신호 없음
0 XP0/32 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"payload 는 제출 누른 순간 얼어. 그 뒤로 세상이 건드릴 수 있는 건 상태 플래그 하나뿐이야."

턴 하나 안에 상태가 두 종류 있어

캡처한 턴 안엔 성격이 완전히 다른 상태 두 종류가 들어 있어. 그 둘을 갈라놓는 게 끊김을 무해하게 만드는 핵심이야.

  • payload. 질문 텍스트랑 이미지 blob 이야. 캡처하는 순간부터 안 바뀌어. 네트워크에서 무슨 일이 나든, 앱이 죽든, 재시도를 하든 이건 다시 안 써.
  • sync 상태. pending → sending → answered | failed 로 움직여. 바뀌는 건 여기뿐이고, 한 칸 옮겨갈 때마다 저장까지 끝나는 쓰기가 일어나.

턴을 이렇게 보면 '전송 중에 앱이 죽으면 어떻게 돼?' 에 시시하고 정확한 답이 나와. payload 는 손도 안 탔고(얼어 있고 이미 박혀 있었으니까), 상태는 아직 sending 이거나 벌써 failed 로 넘어갔거나 둘 중 하나야. 어느 쪽이든 다음에 앱을 켰을 때 뭘 할지가 명확해. 끊김은 데이터가 날아가는 사건이 아냐. 상태가 한 칸 움직이는 사건이야.

payload 가 안 바뀌는 게 왜 중요하냐면

끊김이 payload 를 건드릴 수 있으면 실패 하나하나가 전부 손상 후보가 돼. 질문을 다시 인코딩하는 재시도, 반쯤 쓰인 blob 을 다시 읽는 백그라운드 sync, 필드 두 개 업데이트하다 난 크래시. 하나하나가 사용자가 실제로 쓴 말을 동의도 없이 바꿔놓는 통로야. 캡처할 때 payload 를 얼려놓고 상태만 움직이게 하면, 그 넓은 실패 모드 공간이 작고 훤히 아는 상태 기계 하나로 접혀. '크래시 나고 내 데이터 아직 멀쩡한가?' 라는 무서운 질문이 '지금 어느 상태지?' 로 바뀌어. 답이 넷뿐이고 넷 다 안전한 질문으로.

상태 기계가 곧 계약

상태 전이를 대놓고 설계해 놓으면 견고함이 따라와. payload 를 지우는 전이는 없어. '잃음'을 뜻하는 상태도 없고. 제일 나쁜 게 failed 인데, 그것도 턴을 통째로 쥔 채로 다시 해보자고 할 뿐이야. 약속이 눈에 보이는 형태로 나온 게 이거야. 끊긴 턴은 절대 사라지지 않아. 작고 안전한 지도 어딘가에서 기다리고 있을 뿐이야.

Code

payload 는 얼고, 상태만 움직여·typescript
// payload 는 캡처 후 readonly. 끊김은 상태만 건드림.
type CapturedTurn = {
  readonly deviceTurnId: string;
  readonly question: string;          // 제출 때 얼음
  readonly attachmentIds: string[];   // 제출 때 얼음
  syncStatus: "pending" | "sending" | "answered" | "failed"; // 유일한 손잡이
  answer?: string;                    // 성공 시 한 번 설정
};

// 합법 전이는 작고 안전한 지도를 이뤄:
//   pending  -> sending
//   sending  -> answered | failed
//   failed   -> sending        (재시도)
// 어느 전이도 question/attachmentIds 를 삭제 안 해. '잃음'은 상태가 아냐.

Exercise

캡처한 턴의 상태 기계를 통째로 그려 봐. 상태 전부, 허용되는 전이 전부, 각각의 트리거까지. 그다음 payload 를 잃는 전이를 하나 넣어 보려고 해 봐. 그리고 그게 안 된다는 걸 확인해. 안전한 상태 중에 삭제를 가리키는 게 하나도 없거든. 마지막으로 어느 전이가 저장까지 끝나는 쓰기인지 표시해. 전부야. 그 다이어그램이 캡처 먼저 약속을 그림 한 장에 담은 거야.
Hint
상태는 pending, sending, answered, failed. 트리거는 제출, drain 시작, 배달 성공, 배달 에러, 재시도. lost 노드는 일부러 안 뒀어. 그 노드가 없다는 게 핵심이야.

Progress

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

댓글 0

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

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