"쓰기 전에, 쓸 참이라고 적어. 결제와 기록 사이의 크래시가 비싼 놈이야."
보이지 않는 청구
유료 전사 API 를 부르는 순진한 방법은 이래. 요청 보내고, 응답 받고, 저장하고. 안 되는 순간이 오기 전까지는 잘 돌아가. 근데 그 실패가 유독 고약해. 돈이 드니까. provider 가 청구한 뒤, 결과를 저장하기 전에 크래시가 떨어진다고 해봐. 갖고 있지도 않은 전사에 돈을 낸 거야. 더 나쁜 건 결제했다는 기록이 어디에도 없다는 거고. 돈이 조용히 나간 거지. 영상 수천 개짜리 run 이면 그런 보이지 않는 청구 몇 건은 놓치기 쉽고, 나중에 재구성할 수도 없어.
근본 문제는 이거야. 되돌릴 수 없는 행위, 그러니까 돈 쓰기가 그걸 하겠다는 의도의 durable 기록도 없이 일어났다는 것. 지출이 기록되는 유일한 자리가 저장에 실패한 그 응답이라면, 응답을 잃는 순간 청구 사실 자체가 통째로 사라져.
의도를 먼저 기록해
Recall 은 순서를 바꿔서 고쳐. 유료 호출을 하기 전에 executor 는 반드시 control plane 의 예약 ledger 를 건너야 해. 예약은 '나 이 작업에 돈 쓸 참이야' 라고 말하는 durable 한 행이야. POST 가 나가기 전에 쓰이고 커밋돼. 예약이 생긴 다음에야 유료 호출이 일어나고, 결과는 그 예약에 다시 기록되고.
이제 크래시를 다시 따라가 보자. executor 가 예약하고 POST 전에 죽으면, ledger 에 완료 응답이 없는 예약이 보여. 문제가 된 호출이 정확히 뭔지 아는 거지. 결제하고 결과를 기록하기 전에 죽어도 똑같아. 예약이 바로 거기서 확인해야 할 호출을 가리키고 있어. 지출이 안 보이는 일은 생길 수가 없어. 돈이 움직이기 전에 그 의도가 durably 기록됐으니까.
이건 돈을 위한 write-ahead logging 이야
이 모양은 전에도 봤을 거야. 이름만 달랐을 뿐이지. write-ahead logging 을 하는 DB 는 뭘 할 참인지를 하기 전에 먼저 기록해. 쓰는 도중에 크래시가 나도 복구되게. 결제 시스템은 청구를 capture 하기 전에 authorization hold 를 걸어. 돈이 움직이기 전에 움직이겠다는 의도가 먼저 있게. Recall 은 같은 원리를 유료 API 호출에 적용해. 되돌릴 수 없는 행위보다 의도의 durable 기록이 먼저 온다. 예약은 지출을 위한 write-ahead log 인 거야. 이 트랙의 나머지 전부, identity 도 모호함도 재시도 정책도, 의도가 먼저 적혔다는 사실 위에 지어졌고.