Slide 1

Slide 1 text

STORES 株式会社 Sidekiq その前に: Webアプリケーションにおける 非同期ジョブ設計原則 morihirok Kaigi on Rails 2025

Slide 2

Slide 2 text

自己紹介 森弘 一茂 X: @_morihirok GitHub: morihirok STORES 株式会社 東京Ruby会議12 https://speakerdeck.com/morihirok/ruby-on-rails-nole-simifang

Slide 3

Slide 3 text

非同期ジョブ 使ってる人🙋

Slide 4

Slide 4 text

https://speakerdeck.com/moro/dynamic?slide=41

Slide 5

Slide 5 text

https://speakerdeck.com/moro/dynamic?slide=41

Slide 6

Slide 6 text

今ここ

Slide 7

Slide 7 text

非同期 ジョブ! 非同期 ジョブ! 今ここ

Slide 8

Slide 8 text

非同期ジョブあるある ● 本番環境で何かおきたとき、非同期ジョブによって原因や 影響範囲の特定に時間がかかる ● 非同期ジョブが途中で失敗し、総合的に何がどうなったの かわからなくなる ● 長時間に及ぶ非同期ジョブによって、デプロイやメンテナ ンスインに影響を与えてしまう

Slide 9

Slide 9 text

今日のテーマ 非同期ジョブの 考え方について 整理し理解する

Slide 10

Slide 10 text

目次 1. なぜWebアプリには非同期ジョブが必要なのか 2. 非同期ジョブを使う前に考えること 3. 非同期ジョブの設計原則・指針 4. どのように原則を破るか

Slide 11

Slide 11 text

なぜWebアプリには 非同期ジョブが必要なのか

Slide 12

Slide 12 text

Webサーバは 長時間リクエストを 許容しにくい

Slide 13

Slide 13 text

● Webサーバは基本的に1リクエストを1プロセス/スレッド で処理する Webサーバのしくみ Webサーバ プロセス/スレッド プロセス/スレッド プロセス/スレッド

Slide 14

Slide 14 text

● プロセス/スレッド数以上のリクエストが同時に来ると待 ち行列に入る Webサーバのしくみ Webサーバ プロセス/スレッド プロセス/スレッド プロセス/スレッド

Slide 15

Slide 15 text

● プロセス/スレッドが占有される ● 後続のリクエストを残されたプロセスで処理しなければな らなくなる 長時間リクエストが発生すると、Webサーバは困る Webサーバ プロセス/スレッド プロセス/スレッド プロセス/スレッド

Slide 16

Slide 16 text

● サーバがいわゆる「詰まっている」状態に 長時間リクエストが頻発すると本当に困る Webサーバ プロセス/スレッド プロセス/スレッド プロセス/スレッド

Slide 17

Slide 17 text

長時間リクエストは他にもこんな問題がある ● クライアント側からタイムアウトで打ち切られる ● リソースを占有するような処理だと他のプロセス/スレッ ドに影響を与える ● 1リクエストで様々な処理を行っていると観測しづらい ● 途中で失敗するとシステムの整合性を崩す危険がある

Slide 18

Slide 18 text

● とはいえ1サーバのリソース(CPU/メモリなど)は有限で あり、増やせる数に限界がある Q: プロセス/スレッド数を増やせばよいのでは? Webサーバ プロセス/スレッド プロセス/スレッド プロセス/スレッド プロセス/スレッド

Slide 19

Slide 19 text

● とはいえサーバを増やすのはコストがかかる Webサーバ Webサーバ Q: サーバを増やせばよいのでは? Webサーバ プロセス/スレッド プロセス/スレッド プロセス/スレッド

Slide 20

Slide 20 text

じゃあ長時間になる処理はやめよう! ● とはいえ実際のWebアプリケーションに求められることを 考えると、現実的ではない ● 一括処理、メール送信、外部API実行など、どうしても長 時間になる処理を求められる

Slide 21

Slide 21 text

● 非同期ジョブのプロセス/スレッドに処理を委譲すること で、リクエストが長時間になるのを防ぐ そこで非同期ジョブの出番となる Webサーバ プロセス/スレッド プロセス/スレッド プロセス/スレッド 非同期ジョブ

Slide 22

Slide 22 text

つまり 非同期ジョブは Webアプリを速く&安くする 強力な仕組み

Slide 23

Slide 23 text

非同期ジョブを使う前に考えること

Slide 24

Slide 24 text

それ、本当に 非同期ジョブ 必要ですか?

Slide 25

Slide 25 text

非同期ジョブはシステムに複雑性を持ち込む ● 基本的には同期的に処理するより、非同期ジョブを導入し たほうが処理が複雑になる ● 結果として機能追加や不具合対応の難易度が上がる

Slide 26

Slide 26 text

例題:外部サービスのAPI実行結果をブラウザに表示 Webサーバ 外部サービス ブラウザ ● 非同期ジョブを使わない場合

Slide 27

Slide 27 text

● 非同期ジョブを使う場合 例題:外部サービスのAPI実行結果をブラウザに表示 Webサーバ 外部サービス ブラウザ 非同期ジョブ APIの結果 リクエスト1

Slide 28

Slide 28 text

● 非同期ジョブを使う場合 例題:外部サービスのAPI実行結果をブラウザに表示 Webサーバ 外部サービス ブラウザ 非同期ジョブ APIの結果 リクエスト1 リクエスト2 ポーリング? WebSocket?

Slide 29

Slide 29 text

● 非同期ジョブを使う場合 例題:外部サービスのAPI実行結果をブラウザに表示 Webサーバ 外部サービス ブラウザ 非同期ジョブ APIの結果 リクエスト1 リクエスト2 エラーハンドリン グどうする?

Slide 30

Slide 30 text

● 非同期ジョブを使う場合 例題:外部サービスのAPI実行結果をブラウザに表示 Webサーバ 外部サービス ブラウザ 非同期ジョブ APIの結果 リクエスト1 リクエスト2 アプリのDB使う? 使わない?

Slide 31

Slide 31 text

● 非同期ジョブを使う場合 例題:外部サービスのAPI実行結果をブラウザに表示 Webサーバ 外部サービス ブラウザ 非同期ジョブ 外部APIの結果 リクエスト1 リクエスト2 明らかに意思決定が増え複雑に...

Slide 32

Slide 32 text

非同期ジョブの導入はトレードオフがある ● 外部APIや一括処理であれば非同期ジョブを導入する、と いう機械的な判断はできない ● 複雑さの受け入れ、スループットの向上、ユーザー体験、 様々な事情を天秤にかけ、その都度判断していく必要があ る ● 本当に有効な場面か考えることが重要

Slide 33

Slide 33 text

それ、バッチ処理でも 良くないですか?

Slide 34

Slide 34 text

非同期ジョブじゃなくてバッチ処理でできないか考えてみる ● バッチ処理で行ったほうがシステムがシンプルに設計でき ることがある ○ ユーザーに即時で結果を返す必要がない処理 ○ 大量のデータをまとめて扱う処理処理

Slide 35

Slide 35 text

例題:売上分析機能 ※表示しているのはテストデータなのでご安心ください

Slide 36

Slide 36 text

例題:売上分析機能 Webサーバ ブラウザ 非同期ジョブ 計算結果 リクエスト1 リクエスト2 ● 非同期ジョブを使う場合

Slide 37

Slide 37 text

例題:売上分析機能 Webサーバ ブラウザ 非同期ジョブ 計算結果 リクエスト1 リクエスト2 ● 非同期ジョブを使う場合 ポーリング? WebSocket?

Slide 38

Slide 38 text

例題:売上分析機能 Webサーバ ブラウザ 非同期ジョブ 計算結果 リクエスト1 リクエスト2 ● 非同期ジョブを使う場合 ジョブ失敗時 待たされる ジョブの終わりが 読めない

Slide 39

Slide 39 text

例題:売上分析機能 Webサーバ ブラウザ ● バッチ処理を使う場合 計算結果 バッチ処理 あらかじめ 計算しておく

Slide 40

Slide 40 text

例題:売上分析機能 Webサーバ ブラウザ ● バッチ処理を使う場合 計算結果 バッチ処理 シンプルに作れる!

Slide 41

Slide 41 text

アーキテクチャではすべてがトレードオフ だ。だからこそ、アーキテクチャのあらゆる 問いに共通する答えは、「場合による」なの だ。この答えにいら立つ人は多いだろう。し かし、残念ながらそれが真実だ。 Mark Richards, Neal Ford ソフトウェア アーキテクチャの基礎 p30

Slide 42

Slide 42 text

場合によるからこそ逡巡が起きる

Slide 43

Slide 43 text

非同期ジョブの設計原則・指針

Slide 44

Slide 44 text

Sidekiq の Best Practice より ● Make your job parameters small and simple ○ ジョブのパラメータは小さくシンプルにする ● Make your job idempotent and transactional ○ ジョブは冪等でトランザクショナルにする https://github.com/sidekiq/sidekiq/wiki/Best-Practices Sidekiq に限らない ベストプラクティス

Slide 45

Slide 45 text

非同期ジョブは 短時間で終わる シンプルな処理にする

Slide 46

Slide 46 text

=> 長時間ジョブを避ける

Slide 47

Slide 47 text

例題:注文情報一括処理機能 ※表示しているのはテストデータなのでご安心ください

Slide 48

Slide 48 text

例題:注文情報一括処理機能 ※表示しているのはテストデータなのでご安心ください UIから一括選択でき 一括操作ができる

Slide 49

Slide 49 text

例題:注文情報一括処理機能 ※表示しているのはテストデータなのでご安心ください 選択対象は 10,000件程度になりうる

Slide 50

Slide 50 text

非同期ジョブ 処理 非同期ジョブ 処理 非同期ジョブ 処理 考えうる設計 まとめて処理する設計 分けて処理する設計 非同期ジョブ 処理 処理 処理 処理 非同期ジョブ 処理

Slide 51

Slide 51 text

非同期ジョブ 処理 非同期ジョブ 処理 非同期ジョブ 処理 考えうる設計 まとめて処理する設計 分けて処理する設計 非同期ジョブ 処理 処理 処理 処理 非同期ジョブ 処理 こっちのほうが 短時間でシンプル

Slide 52

Slide 52 text

なぜ?の前に非同期ジョブのしくみについて ● 非同期ジョブも基本的にジョブキューに積まれたジョブを 1つずつ1プロセス/スレッドで処理する 非同期ジョブサーバ プロセス/スレッド プロセス/スレッド プロセス/スレッド ジョブキュー 行列

Slide 53

Slide 53 text

つまり Webサーバと 同じように考えられる!

Slide 54

Slide 54 text

短時間でシンプルなほうが全体のスループットが上がる ● Webサーバと同様に1つのジョブが短時間で終わるほうが 全体のスループットが上がる ● 他ジョブがリソースを占有して処理の遅延が起こるという ケースも減らせる

Slide 55

Slide 55 text

失敗時の再試行において考えることが少なくなる ● 長時間ジョブの途中で失敗した場合にどのように復旧させ るかは悩ましい問題になる ○ 復旧するための設計を別途考えたり... ● 小さくシンプルな処理であれば何も考えずリトライすれば すむケースが多い

Slide 56

Slide 56 text

可観測性も良くなる ● 長時間ジョブは実行状況が見えづらく、観測するためには 別途ログを書き込んだりAPMにツールを送ったりと観測す るための実装を行う必要がある ● 短時間で終わるシンプルなジョブであれば、開始と終了が 観測できれば十分なケースが多い

Slide 57

Slide 57 text

デプロイ時の影響もなくなる ● 非同期ジョブワーカーは多くの場合Webサーバと同様にデ プロイ時にプロセスを停止させる必要がある ● 長時間ジョブがシステムに存在する場合、デプロイ時にま だジョブが動いていたときの考慮が必要になる

Slide 58

Slide 58 text

非同期ジョブ設計原則 非同期ジョブは 短時間で終わる シンプルな処理にする

Slide 59

Slide 59 text

どのように原則を破るか

Slide 60

Slide 60 text

現実的には長時間ジョブは存在しうる ● 実現したいユーザー体験を考えると長時間ジョブでやるし かないというケース ○ なるべくリアルタイム性はほしい ○ 1件ごとの順序性が求めれる ○ 全件成功したら最後に行いたい処理がある ● 長時間ジョブである必要性はないが、すでに目の前に長時 間ジョブが存在しているケース

Slide 61

Slide 61 text

長時間ジョブの運用で考えるべきポイント ● デプロイ・メンテナンスインなどなんらかの理由で途中終 了しうるので、中断・再開ができるように作る ● 長時間ジョブの中で例外が発生したときのハンドリング

Slide 62

Slide 62 text

現代では便利なライブラリがあるのでそれを使うのを推奨 ● https://github.com/Shopify/job-iteration ○ ActiveJobで中断・再開を記述できる ● https://github.com/sidekiq/sidekiq/wiki/Iteration ○ Sidekiqで中断・再開を記述できる

Slide 63

Slide 63 text

Rails 8.1 からActive Job Continuationが導入 https://rubyonrails.org/2025/9/4/rails-8-1-beta-1

Slide 64

Slide 64 text

Sidekiq Pro であれば Batches が使える ● https://github.com/sidekiq/sidekiq/wiki/Batches ● ジョブ自体を小さい粒度に抑えつつ、全体の途中経過を見 れたり完了時のコールバックを差し込むことができたりす る ● 長時間ジョブを避ける設計ができる ● Sidekiq Proを使っていて順序保証が不要な処理であれば 候補になる

Slide 65

Slide 65 text

ちなみにSTORESだとこんな機構があります ● https://github.com/riseshia/sfn_job ● ActiveJob からAWS Step Functions経由でECS Taskを 実行し、ジョブの処理を行う ● 分離されたプロセスで長時間ジョブを実行させることで 諸々の制約から逃れる riseshia a.k.a シムさん

Slide 66

Slide 66 text

まとめ

Slide 67

Slide 67 text

まとめ:非同期ジョブ設計の考え方 本当に非同期ジョブで 作るべきか?

Slide 68

Slide 68 text

まとめ:非同期ジョブ設計の考え方 本当に非同期ジョブで 作るべきか? バッチ処理で作れないか?

Slide 69

Slide 69 text

まとめ:非同期ジョブ設計の考え方 本当に非同期ジョブで 作るべきか? バッチ処理で作れないか? 長時間ジョブを避ける 設計ができないか?

Slide 70

Slide 70 text

まとめ:非同期ジョブ設計の考え方 本当に非同期ジョブで 作るべきか? バッチ処理で作れないか? 長時間ジョブを避ける 設計ができないか? Active Job Continuation などの導入

Slide 71

Slide 71 text

非同期ジョブ設計原則 非同期ジョブは 短時間で終わる シンプルな処理にする

Slide 72

Slide 72 text

72 04 STORES でのカンファレンス活用事例