TT Lab
はじめる
学ぶ 学習パス コース

キューと非同期API

ジョブ投入と状態ポーリングのAPIを作る

TT Labで続きを見る

目標

202 Acceptedで始まる非同期APIの全体の契約(受付、状態取得、ポーリングの調整、冪等な提出、完了通知)を、自分で実装します。

なぜ重要なのか

30秒かかる作業を同期APIで作ると、3つが同時に壊れます。ロードバランサーのアイドルタイムアウトにかかり、クライアントのリトライが同じ作業を2回動かし、ワーカーが30秒ずつ塞がります。非同期APIは、これを受付と確認に分けます。ところが、202を返すだけで終わるAPIが、意外に多くあります。クライアントは、結果をどこで見ればよいかを知らず、どれだけ待てばよいかを知らず、リトライしてよいかもわかりません。このラボは、その契約の欠けた部品を1つずつ埋めます。Locationヘッダー、状態の語彙、Retry-After、冪等キー、そしてWebhookです。これらをすべて備えれば、その時点からクライアントは、安心してリトライできます。

ステップ

  1. /root/aj/api.pyを127.0.0.1:8140で起動します。POST /jobsは{"n":5}を受け取って、キューq:jobs2に入れます。
  2. POST /jobsの応答は202で、Location: /jobs/<job_id>ヘッダーと、本文{"job_id":"...","status":"queued"}を返します。
  3. GET /jobs/<job_id>は、200とstatusを返します。値は、queued、running、succeeded、failedのいずれかです。存在しないidは404です。
  4. /root/aj/worker.pyは、キューから取り出して状態をrunningに変え、処理後にsucceededに変えます。
  5. 完了したジョブの取得の応答に、resultキーがある必要があります。queuedの状態では、resultキーがあってはいけません。
  6. queuedまたはrunningの状態の応答には、Retry-Afterヘッダーが整数の秒数で付き、succeededの応答には付きません。
  7. 同じIdempotency-Keyで2回提出すると、同じjob_idを返し、キューには1件だけ入ります。
  8. /opt/app/hooksink.pyを127.0.0.1:8141で起動します。提出時にcallback_urlも一緒に受け取り、完了時にそのアドレスにPOSTします。/root/aj/hook.logに、job_idとstatus=succeededが記録されます。

参考

ジョブ提出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です。

状態の語彙は、4つで十分です。存在しないjob idには404を返してください。

ワーカーが状態を遷移させる

/root/aj/worker.pyは、キューから取り出して状態をrunningに変え、処理後にsucceededに変えてください。

キューから取り出したらrunning、終わったらsucceededです。状態はRedisのハッシュに置くと便利です。

完了後に結果を入れる

完了したジョブの取得の応答に、resultキーがあるようにしてください。queuedの状態では、resultキーがあってはいけません。

結果が小さければ、状態の応答に一緒に入れてもかまいません。完了前には、resultキーがあってはいけません。

ポーリング間隔を提案する

queuedまたはrunningの状態の応答には、Retry-Afterヘッダーが整数の秒数で付き、succeededの応答には付かないようにしてください。

進行中のときだけ、ヘッダーを付けます。完了した応答にこのヘッダーがあると、クライアントがポーリングし続けます。

提出を冪等にする

同じIdempotency-Keyで2回提出すると、同じjob_idを返し、キューには1件だけ入るようにしてください。

202を受け取る前に接続が切れると、クライアントはリトライします。同じキーには、同じ識別子を返してください。

完了のWebhookを送る

/opt/app/hooksink.pyを127.0.0.1:8141で起動してください。提出時にcallback_urlも一緒に受け取り、完了時にそのアドレスにPOSTします。/root/aj/hook.logに、job_idとstatus=succeededが記録されます。

受信側を先に起動し、提出するときにコールバックのアドレスも一緒に受け取ります。受信の記録が残って初めて採点されます。