ジョブ投入と状態ポーリングのAPIを作る
한국어 원문으로 표시합니다.
목표
202 Accepted 로 시작하는 비동기 API 의 전체 계약 — 접수, 상태 조회, 폴링 조절, 멱등 제출, 완료 통보 — 를 직접 구현한다.
왜 중요한가
30초 걸리는 작업을 동기 API 로 만들면 세 가지가 동시에 깨집니다. 로드밸런서 유휴 타임아웃에 걸리고, 클라이언트 재시도가 같은 작업을 두 번 돌리고, 워커가 30초씩 묶입니다. 비동기 API 는 이것을 접수와 확인으로 나눕니다. 그런데 202 만 돌려주고 끝내는 API 가 의외로 많습니다. 클라이언트는 결과를 어디서 봐야 할지 모르고, 얼마나 기다려야 하는지 모르고, 재시도해도 되는지 모릅니다. 이 실습은 그 계약의 빠진 조각들을 하나씩 채웁니다 — Location 헤더, 상태 어휘, Retry-After, 멱등성 키, 그리고 웹훅입니다. 이것들을 다 갖추면 그때부터 클라이언트가 안심하고 재시도할 수 있습니다.
단계
/root/aj/api.py를 127.0.0.1:8140 에 띄운다.POST /jobs는{"n":5}를 받아 큐q:jobs2에 넣는다.POST /jobs응답은 202 이고Location: /jobs/<job_id>헤더와 본문{"job_id":"...","status":"queued"}를 준다.GET /jobs/<job_id>는 200 과status를 준다. 값은queued,running,succeeded,failed중 하나이다. 없는 id 는 404 이다./root/aj/worker.py는 큐에서 꺼내 상태를running으로 바꾸고 처리 후succeeded로 바꾼다.- 완료된 작업 조회 응답에
result키가 있어야 한다.queued상태에서는result키가 없어야 한다. queued또는running상태 응답에는Retry-After헤더가 정수 초로 붙고,succeeded응답에는 붙지 않는다.- 같은
Idempotency-Key로 두 번 제출하면 같은job_id를 돌려주고 큐에는 1건만 들어간다. /opt/app/hooksink.py를 127.0.0.1:8141 에 띄운다. 제출 시callback_url을 함께 받아 완료 시 그 주소로 POST 한다./root/aj/hook.log에job_id와status=succeeded가 기록된다.
참고
- 202 는 '했다'가 아니라 '받았다'입니다. Location 이 없으면 계약이 미완성입니다.
- 완료된 작업 상태에는 TTL 을 두고, 만료 조회에는 404 대신 410 Gone 을 주면 클라이언트가 구별할 수 있습니다.
- 흔한 실수 1: job id 로 아직 만들어지지 않은 결과 리소스의 ID 를 쓰는 것 — 실패하면 유령 ID 가 남습니다.
- 흔한 실수 2: 완료 응답에도
Retry-After를 붙여 클라이언트가 영원히 폴링하게 만드는 것.
작업 제출 API 띄우기
/root/aj/api.py 를 127.0.0.1:8140 에 띄운다. POST /jobs 는 {"n":5} 를 받아 큐 q:jobs2 에 넣는다.
제출은 큐에 넣고 바로 답합니다. 실제 처리는 하지 마세요 — 그게 비동기의 핵심입니다.
202 와 Location 헤더 돌려주기
POST /jobs 응답은 202 이고 Location: /jobs/<job_id> 헤더와 본문 {"job_id":"...","status":"queued"} 를 준다.
'받았다'와 '어디서 확인하는가'가 함께 있어야 계약이 성립합니다. 헤더와 본문 둘 다 필요합니다.
상태 조회 엔드포인트 만들기
GET /jobs/<job_id> 는 200 과 status 를 준다. 값은 queued, running, succeeded, failed 중 하나이다. 없는 id 는 404 이다.
상태 어휘는 네 개로 충분합니다. 없는 job id 에는 404 를 주세요.
워커가 상태를 전이시키기
/root/aj/worker.py 는 큐에서 꺼내 상태를 running 으로 바꾸고 처리 후 succeeded 로 바꾼다.
큐에서 꺼내면 running, 끝나면 succeeded 입니다. 상태는 Redis 해시에 두면 편합니다.
완료 후 결과 담기
완료된 작업 조회 응답에 result 키가 있어야 한다. queued 상태에서는 result 키가 없어야 한다.
결과가 작으면 상태 응답에 함께 담아도 됩니다. 완료 전에는 result 키가 없어야 합니다.
폴링 간격 제안하기
queued 또는 running 상태 응답에는 Retry-After 헤더가 정수 초로 붙고, succeeded 응답에는 붙지 않는다.
진행 중일 때만 헤더를 줍니다. 완료된 응답에 이 헤더가 있으면 클라이언트가 계속 폴링합니다.
제출을 멱등하게 만들기
같은 Idempotency-Key 로 두 번 제출하면 같은 job_id 를 돌려주고 큐에는 1건만 들어간다.
202 를 받기 전에 연결이 끊기면 클라이언트는 재시도합니다. 같은 키에는 같은 식별자를 주세요.
완료 웹훅 보내기
/opt/app/hooksink.py 를 127.0.0.1:8141 에 띄운다. 제출 시 callback_url 을 함께 받아 완료 시 그 주소로 POST 한다. /root/aj/hook.log 에 job_id 와 status=succeeded 가 기록된다.
수신기를 먼저 띄우고 제출할 때 콜백 주소를 함께 받습니다. 수신 기록이 남아야 채점됩니다.