증상
건수가 많은 작업을 한 HTTP 요청 안에서 동기로 처리했더니 응답이 안 돌아온다. 부분 처리분은 커밋됐는데 응답이 없어 진행 상태를 알 수 없다(재시도하면 중복 위험).
타임아웃은 하나가 아니다 — 이게 핵심이다
이 지뢰를 네 번 밟는 동안 매번 더 빡빡한 타임아웃이 하나씩 더 나왔다.
| 축 | 성격 |
|---|---|
| 워커 타임아웃 | 내가 정한다. 늘릴 수 있다 |
| 외부 스케줄러 타임아웃 | 못 늘린다. 플랫폼 하드 상한이다 |
| 항목당 최악 지연 | 외부 의존이라 보장이 없다 |
★ 건수 캡(limit)은 시간 캡이 아니다. limit=10에 항목당 최악 8초면 80초다. 워커 타임아웃은 안 넘는데 외부 스케줄러의 30초를 넘긴다.
중간 처방과 그 한계 (남겨둘 값어치가 있다)
처음엔 벽시계 예산으로 갔다 — 항목마다 착수 *전에* 경과를 확인하고, 예산에 닿으면 중단하고 {처리분, 잔여, 예산소진}을 200으로 반환. 남은 건 다음 호출이 이어받는다. 한 건씩 잡아 처리·커밋하면 중단 시 미처리 잔재가 0이 된다.
이걸로도 안 됐다. 두 가지 때문이다.
확정 처방 — 예산 역산이 아니라 즉답
작업 예산 < 스케줄러 간격 < 워커 타임아웃
결과
http=202 · 0.24초. 즉답 설계라 큐 길이와 무관하게 상수 시간이 된다. 하드 상한 대비 여유가 100배 이상이면 그 축은 고민 대상에서 사라진다.
규율
호출자의 타임아웃이 플랫폼 하드 상한이고 작업이 그 안에 안 끝날 수 있으면, 예산으로 깎지 말고 즉답 + 백그라운드 + 멱등 재개 + 중복 가드로 간다. 예산 깎기는 상한을 늘릴 수 있을 때만 유효하다.
상태 저장소를 따로 만들지 않는다
작업 대상 자체를 상태로 쓴다(초안/발행/메타플래그가 곧 진행상태). 별도 잡스토어 없이 무상태 재개가 된다. 작업이 이미 멱등·재개 가능하면 백그라운드 스레드가 고아가 돼도 다음 호출이 이어받는다.
후속 — 할 일이 0일 때의 비용을 먼저 본다
잔여 0인데도 한 틱이 30초 넘게 걸렸다. 원인은 틱이 전체 목록을 매번 두 번 조회하는 것이었다. 할 일이 없어도 그 고정비를 태운다.
→ 수렴 후 즉시 skip하는 완료 캐시, 목록은 틱당 1회만 조회해 공유, 그리고 '대상 0'을 대상 없음(정상) vs 조회 실패(이상) 로 구분해 로그한다.
★ 주기 작업의 튜닝은 고정비를 없앤 뒤에 측정하고 결정한다.