"몇 시간짜리 일을 소유한 요청은 노트북 닫아서 죽일 수 있는 job 이야."
솔깃한 실수
'이 아카이브 전사해줘' 를 만드는 뻔한 방법은 그 일을 직접 하는 요청 핸들러야. 브라우저가 endpoint 를 부르면 핸들러가 영상을 하나씩 돌면서 전사하고, 아카이브가 끝나면 return 하고. 데모에선 돌아가. 프로덕션에선 재앙이고. 요청만큼 부서지기 쉬운 소유자가 없거든. 요청의 수명은 TCP 연결에, 브라우저 탭에, 호텔 Wi-Fi 신호에, 노트북 뚜껑에 묶여 있어. 그중 아무거나 끝나는 순간 몇 시간짜리 job 이 반쯤 된 채로 죽어. 깔끔하게 재개할 방법도 없이.
더 깊은 문제는 timeout 이 아니라 소유권이야. 요청이 일을 소유하면 그 일은 요청이 살아 있는 동안만 존재해. 그런데 요청은 애초에 짧게 살라고 설계된 거잖아. 버려지라고 만든 그릇에 몇 시간짜리 가치를 담은 셈이야.
계획, enqueue, 관찰 — 절대 소유 안 함
Recall 은 그걸 뒤집어. 요청은 전사를 절대 안 돌려. 값싸고 빠른 세 가지 중 하나만 하고 바로 return 해.
- 계획(Plan) — run 이 뭘 할지(어떤 영상을 몇 개) 아무것도 안 쓰고 계산해.
- enqueue — durable batch 와 그 queued job 을 DB 에 만들고 batch id 를 돌려줘. 밀리초면 끝나.
- 관찰(Observe) — 이미 돌고 있는 batch 의 현재 상태와 진행과 ETA 를 읽어.
실제 몇 시간짜리 전사는 persistent worker 가 소유해. 운영체제의 서비스 매니저가 살려두는, 어떤 요청과도 무관한 프로세스야. queued job 을 claim 해서 누가 보든 말든 갈아. 그래서 operator 노트북 연결을 끊든 status 명령을 죽이든 batch 엔 아무 일도 안 생겨. 애초에 일이 요청에 있었던 적이 없거든. 요청은 durable 한 의도만 적어두고 자리를 떴을 뿐이야.
테스트: 노트북을 닫아
제대로 했는지 보는 한 줄짜리 테스트가 있어. 일을 시작하고 노트북을 닫아 봐. 계속 돌아? 돌면 그 일은 persistent worker 가 소유하는 durable queue 에 있는 거야. 안 돌면 어떤 요청이 몰래 job 을 인질로 잡고 있는 거고, 네트워크가 한 번만 흔들려도 몇 시간이 날아가. Recall 은 설계상 이 테스트를 통과해. 요청이 하는 일은 뭐가 일어나야 하는지를 durably 기록하는 것 하나고, 그걸 실제로 일어나게 하는 건 모든 요청보다 오래 사는 worker 니까.