C.W.K.
Stream
Lesson 02 of 04 · published

재개 가능한 state machine

~15 min · firelink, state-machine, resumable, saga

Level 0식은 재
0 XP0/32 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"Birth 는 세계를 단계로 만져. 모든 단계는 다음이 시작하기 전에 기억돼 — 그래서 crash 는 잔해가 아니라 save point 를 남겨."

여러 external effect, 순서대로

repo 를 birth 하는 건 한 액션이 아냐; 현실 세계 effect 의 사슬이야. scaffold 준비, 로컬 Git repo 생성, private remote 요청, initial commit push, publish, roster 갱신, network ledger 갱신, operation registry 갱신, 검증. 그 하나하나가 프로세스 바깥의 뭔가를 만져 — 파일시스템, GitHub, ledger 파일. 하나라도 중간에 실패하면, 어느 effect 가 이미 일어났는지 추측하게 남겨져선 안 돼. 그래서 Birth 는 재개 가능한 state machine 으로 돌아. 순서 있는 state 집합, 각각이 완료되는 순간, 다음 external effect 시작 전에 persist 돼.

단계를 persist 하고, 그다음을 잡아

규율은 단순하고 엄격해. 다음 external effect 시작 전에 모든 완료 단계를 persist 해. remote 가 생성됐으면, 그 사실이 push 시도 전에 durable 해. 그래서 push 가 실패하면 run 은 'remote 생성됨'에서 재개돼 — remote 를 다시 안 만들고, repo 를 다시 init 안 하고, 아무것도 두 번 안 해. 실패는 마지막 좋은 state 에 주차된 명시적 resumable run 을 남기고, retry 는 자기 부분 작업과 충돌하는 대신 거기서 이어가. Birth 는 부분 state 에서 절대 complete 라 불리지 않고, 평범한 retry 는 이전 시도의 잔여물과 절대 안 싸워.

staging, 원자적 publish, 그다음 검증

안전 수 두 개가 사슬을 감싸. 첫째, Birth 는 scaffold 를 Firelink 소유 staging 위치에 짓고, 로컬 준비가 완전히 성공한 뒤에만 새 디렉터리를 제자리로 원자적으로 publish 해 — 그래서 반쯤 지어진 껍데기가 진짜 path 에 절대 안 나타나. 둘째, 마지막 단계는 자기 bookkeeping 을 안 믿어. 새 멤버를 FamilyRegistry 와 FamilyReconciler 를 통해 다시 짓고, 성공 보고 전에 올바르게 composed 되는지 확인해. birth 는 단계가 돌아서 끝난 게 아냐; composed·reconciled 된 가족이 실제로 새 멤버를 담아서 끝난 거야.

external side effect 있는 multi-step operation 은, 다음이 시작하기 전에 각 완료 단계를 persist 하고, 실패가 재시작이 아니라 마지막 좋은 state 에서 재개하게 만들어. 어디까지 갔는지 기억하는 사슬은 중간 crash 를 '알 수 없는 손상'에서 '여기서 이어가'로 바꿔 — 그리고 성공의 최종 증명은 단계가 돌았다고 믿는 게 아니라 결과를 다시 도출하는 거야.

Code

각 external 단계가 다음 전에 durable state 가 된다·bash
# Birth orchestrates real effects. Each completes and is PERSISTED as a
# state before the next external effect starts, so a crash is resumable.

git init cwkNewThing                       # -> state: local-git-created   (persist)
git -C cwkNewThing add -A
git -C cwkNewThing commit -m "scaffold shell"   # scaffold only, no product
gh repo create cwkNewThing --private       # -> state: private-remote-created (persist)
git -C cwkNewThing push -u origin main     # -> state: initial-push-complete  (persist)

# If the push dies HERE, the run is parked at 'private-remote-created'.
# The retry resumes from there: it does NOT re-init the repo or re-create
# the remote. No step is repeated, no partial work is fought.
#
# ...then roster-updated -> network-updated -> registry-updated ->
#    registry-VERIFIED (rebuild via FamilyRegistry+Reconciler) -> complete.

External links

Exercise

external 시스템을 하나 넘게 만지는, 네가 짓거나 쓴 multi-step operation 을 스케치해 (유저 생성 + welcome 이메일 + workspace provisioning, 예를 들어). 단계를 순서대로 나열해. 이제 4단계 중 2단계 후 crash 를 상상해. 네 설계가 어디서 멈췄는지 정확히 알아, 그리고 retry 가 1·2단계 다시 안 하고 재개할 수 있어? 아니면, 각 단계 후 persist 된 state 를 더하고 retry 가 그걸 어떻게 쓰는지 설명해.
Hint
사냥할 failure mode: 1단계가 이미 성공했다고 아무것도 기록 안 해서 retry 가 1단계를 다시 도는 것(두 번째 유저, 두 번째 이메일). 고침은 N+1 단계 시작 전에 쓰인 durable '단계 N 완료' 마커야 — Birth 의 state 와 같은 모양.

Progress

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

댓글 0

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

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