ユニファ開発者ブログ

ユニファ株式会社プロダクトデベロップメント本部メンバーによるブログです。

日時指定でワンタイムでJobを実行したい時はSidekiqのperform_atを使うと便利

こんにちは。サーバーサイドエンジニアの船曵です。 今回の記事は書きたいことがタイトルに全て収まってしまいました。

CSVからデータ取り込む場合に、特定日時指定で実行したいケースが時々あります。 この「時々」というのがポイントで、時々ゆえに機能化するかどうかは微妙で、定期実行したいわけではないので、スケジューラの設定ファイルに書き加えたい内容でもない。 当日を待って実行しても良いのですが、シンプルな方法で予約しておけるなら便利そうです。

何か簡単にできる方法ないかなと探していたところ、Sidekiqやresque-schedulerで時間指定実行できる機能を見つけました。

参考

github.com

github.com

今まで定期実行または遅延処理という使い方がほとんどだったため、時間指定できることを知りませんでした。 公式ページは大事な情報が詰まっています。

今回はSidekiqを使って、実験用のコードで日時指定実行を試してみたいと思います。 実験環境はRails + sidekiqです。

# Sidekiqの機能を使用するので、ApplicationJobは継承しません。
class HelloWorker
  include Sidekiq::Worker
  sidekiq_options queue: :queue_name #実際に使っているキュー名を指定する
  def perform(*args)
    Rails.logger.info "Hello Worker"
  end
end

実行結果をすぐ確認したいので、今回は 16:16現在の2分後である、16:18に上記のworkerを起動するように設定しました。 設定後に現在時刻を確認します。

今回は日時指定したいため、2分後の「時刻」という形で値を渡していますが、例えば15分後に実行したいといった相対的な時間指定をしたい場合は perform_atではなく、perform_in(15.minutes)で実施すればOKそうです。

一連の処理はRails Consoleから実行し、ログで結果を確認します。

# 2分後の日時を取得
perform_at = 2.minutes.from_now
=> Tue, 30 Apr 2024 16:16:18 JST +09:00

# 2分後の日時に起動するように設定
# 引数を渡したいときは第2引数以降に指定する
HelloWorker.perform_at(perform_at)
=> "573c1752280fde7fa53184cf"

# 現在時刻を確認する
Time.current
=> Tue, 30 Apr 2024 16:14:22 JST +09:00

ログ

2024-04-30 16:16:42.533643 D [1:46912556824720] Sidekiq-server -- enqueued schedule: {"class":"HelloWorker","args":[],"retry":true,"queue":"middle","jid":"573c1752280fde7fa53184cf","created_at":1714461271.6564388}
2024-04-30 16:16:42.753869 I [1:46912556823500] Rails -- Hello Worker

HelloWorker.perform_at(perform_at) コマンドを実行したのが、16:14:22、enqueuedされたのが16:16:42 実行するまでにおよそ2分経過しており、秒までの正確性はなさそうですが、ほぼ期待値通りの結果を確認しました。 これでいつでも、非同期で指定日にデータ連携が可能になりました!

将来的に機能化したくなった時は、S3にCSVファイルがアップロードされたのをトリガーにでエンキューする、みたいなことをしたい気もしつつ、冪等性やエラーハンドリングなど、考慮すべき課題も多いので、それはまた別の機会に検討してみたいと思います。


ユニファでは一緒に働く仲間を募集しています。記事公開時点ではプロダクトデザイナーも募集中です!

ご興味を持っていただけましたらぜひ採用情報をチェックしてみてください! jobs.unifa-e.com