Sidekiqのベストプラクティス
概要
Sidekiqのベストプラクティスに沿って、メッセージ機能を実装していきます。
0. Sidekiqとは
Sidekiqとはbackgroundでタスクを処理してくれるライブラリです。日付指定でセットして実行したりもできます、便利そうです。
ベストプラクティスに沿ってWorker用のテーブルを用意します。
# messages class CreateMessages < ActiveRecord::Migration[5.1] def change create_table :messages do |t| t.integer "sender_id" t.integer "recipient_id" t.string "body" t.timestamps end end end
# message_tasks class CreateMessageTasks < ActiveRecord::Migration[5.1] def change create_table :message_tasks do |t| t.integer "sender_id" t.integer "recipient_id" t.string "body" t.timestamps end end end
今回はミニマムのデモのため構造は全く同じですが、実際は送信するユーザが複数だったりプッシュ通知をしたりするかもしれません。
1. ジョブのパラメータを小さく・シンプルに
上記のMessageTasks
のテーブルを用意することで、引数をtask_id
のみにすることができます。
class MessageWorker include Sidekiq::Worker def perform(task_id) end end
また呼び出し側では以下のようになります。
task = MessageTask.create(sender_id: sender_id, recipient_id: recipient_id, body: body) MessageWorker.perform_async(task.id)
2. 冪等性とトランザクション
perform
内でエラーが発生した場合、自動リトライ機能が働きます。デフォルトでは25回のリトライ後(おおよそ21日後)そのジョブは削除されマニュアルで対応しないといけません。
それを防ぐためにもMessageTasks
とトランザクションを使用することで、より安全にデータを扱うことができます。
class MessageWorker include Sidekiq::Worker def perform(task_id) task = MessageTask.find(task_id) if task.nil? return end ActiveRecord::Base.transaction do Message.create(sender_id: task.sender_id, recipient_id: task.recipient_id, body: task.body) task.destroy end end end
3. Concurrencyの設定
Concurrencyを設定することによりsidekiqの処理を並列化することが可能です。デフォルト値は25スレッドで推奨値は50未満。100以上設定した場合、安定性の問題があるとの。
config/database.yml
を変更することで変えることができます。この値は可変ではないので、用途に応じて変更する必要があるようです。
production: adapter: mysql2 database: foo_production pool: 25
まとめ
Sidekiqを使うことで同期処理が必要がないタスクは非同期で処理させることができます。同期処理させる必要ないものは非同期にしてレスポンス速度を改善できそうですね。