コンテンツにスキップ

PostgreSQLで作る非同期ジョブキュー

チェック

  • [ ] 本文を確認した
  • [ ] 概要を確認した
  • [ ] タグを確認した
  • [ ] inbox/ 直下へ移行した

概要

PostgreSQL を使って非同期 job queue を実装する記事。 外部 queue service を導入せず、DB transaction と row lock を使って job の取得、実行、retry、状態管理を行う設計を扱う。 小から中規模のバックエンドでは、既存 DB に寄せることで運用対象を増やさずに非同期処理を始められる。

本文

PostgreSQL に job table を用意し、pending / running / succeeded / failed のような状態を持たせる。 worker は pending job を取得して running に更新し、処理完了後に succeeded または failed に更新する。

複数 worker が同時に動く場合は、同じ job を二重取得しないために lock が必要。 PostgreSQL では FOR UPDATE SKIP LOCKED を使うことで、別 transaction が lock している行を飛ばしながら job を取得できる。 これにより、複数 worker が同じ queue table から安全に job を取り出せる。

retry では、attempt count、next_run_at、last_error などを job table に持つ。 失敗した job は即座に再実行するのではなく、backoff をかけて次回実行時刻を更新する。 一定回数を超えたら dead letter 相当の状態にする。

PostgreSQL queue の利点は、既存 transaction と同じ DB 内で job enqueue できること。 たとえば業務データの更新と job 作成を同一 transaction に含めれば、DB 更新だけ成功して job が作られない事故を防ぎやすい。

一方で、巨大な queue や高 throughput が必要な場合は専用 queue service の方が向く。 DB queue は index、vacuum、table bloat、lock、監視を含めて設計する必要がある。

要点

  • FOR UPDATE SKIP LOCKED は PostgreSQL job queue の中核になる。
  • 業務 data 更新と job enqueue を同一 transaction にできる。
  • Retry、backoff、dead letter、監視を設計する。
  • 高 throughput / 長期大量 job では専用 queue も検討する。

タグ

postgresql #job-queue #transaction #backend #database