"'실패하면 재시도' 는 그 실패가 아무것도 안 했다고 조용히 가정해. 유료 호출엔, 그 가정이 도박이야."
가장 반사적인 좋은 관행이, 함정으로
네트워크 호출을 자동 재시도로 감싸는 건 워낙 표준 위생이라 HTTP client 대부분이 기본으로 해줘. 그리고 재시도가 원래 겨냥한 작업, 그러니까 idempotent 하고 부작용 없는 읽기에는 정확히 맞는 얘기야. 호출이 아무 효과도 못 냈거나 알 수 없었을 뿐이고, 어느 쪽이든 다시 돌려도 무해하니까. 유료 전사 호출은 그 둘 중 어느 쪽도 아냐. 돈을 움직이고, 한 번 제출되면 이미 돌았을 수도 있어. 그래서 Recall 은 얼핏 보면 틀려 보이는 걸 해. 유료 호출을 하는 client 에서 자동 재시도를 아예 없애버려.
이유는 분명해. 요청을 제출한 뒤에 난 transport timeout 은 provider 가 job 을 돌렸는지에 대해 아무것도 안 알려줘. provider 가 전사하고 청구까지 했는데 응답만 오는 길에 잃어버린 걸 수도 있어. 그 순간의 자동 재시도는 눈 감고 하는 두 번째 구매야. 유료 경계를 넘어서까지 적용된 재시도 반사는 회복력으로 분장한 돈 누수고.
유료 경계가 선이야
답은 '절대 재시도하지 마' 가 아냐. '되돌릴 수 없는 행위가 정확히 어디 있는지 알고, 자동 재시도가 그 선을 절대 못 넘게 하라' 는 거지. Recall 은 유료 POST 에 단단한 선을 하나 그어.
- 경계 전 — source hash, 오디오 proxy 빌드, ledger 예약. 여기까지는 돈을 한 푼도 안 썼어. 그래서 여기서 난 실패는 재시도해도 안전해. 첫 시도가 아무 비용도 안 들었다는 게 증명되니까. Recall 은 딱 이걸 작업으로 노출해. '유료 경계 전에 난 게 확실한 실패만 재시도' 하는 작업.
- 경계에서, 또는 그 뒤 — POST 가 이미 나갔어. 여기서 난 실패는 무해하다는 걸 증명 못 하니까 절대 자동 재시도 안 해. 지난 레슨의 ambiguous 상태가 돼서 사람한테 넘어가.
그러니까 재시도가 금지된 게 아니라 선이 그어진 거야. 엔진은 값싸고 아무 효과도 없었다는 게 증명되는 쪽에서는 마음껏 재시도하고, 돈 경계에서 딱 멈춰. 기술은 그 경계가 정확히 어디 앉는지를 아는 거고. 자동 재시도는 첫 시도가 아무것도 안 했다는 증명만큼만 안전하거든.
회복력은 재시도랑 같은 게 아냐
이 반사가 워낙 깊으니까 분명히 짚고 갈게. 시스템은 자동 재시도를 거부하면서도 얼마든지 회복력이 강할 수 있어. Recall 은 크래시도, 연결 끊김도, provider timeout 도 버텨. 근데 유료 endpoint 를 눈 감고 다시 때려서가 아니라 durable 예약과 outbox 와 idempotent 수락으로 버티는 거야. 진짜 회복력은 모든 상태를 복구할 수 있게 만드는 거지, 같은 호출을 될 때까지 두들기는 게 아냐. 작업이 공짜고 idempotent 하면 마음껏 재시도해. 돈이 들거나 부작용이 없다는 걸 증명 못 하면, 회복력은 나중에 복구할 수 있을 만큼 기록해두고 진실을 확인할 수 있는 사람한테 불확실성을 넘기는 거고.