🐕

【Rails7】sidekiq-schedulerで定期的にジョブを実行する

2022/10/03に公開

Rails7で個人開発しているスケジュール通知アプリ(下記/もしよかったら使ってみてください!)で、sidekiq-schedulerというgemを導入してバックグラウンドで定期的にジョブを実行する環境を作りました。そのやり方の備忘録です。

https://torikomi.fly.dev/

環境

アプリは以下の環境で作成しています。

  • macOS 11.6.2
  • Ruby 3.1.2
  • Rails 7.0.3
  • PostgreSQL 14.4

下準備

RailsアプリにSidekiqを導入し、Redisと接続します。下記の記事で、開発環境での環境構築手順をまとめました。

https://zenn.dev/yoiyoicho/articles/03863702867eb0

本番環境にはHerokuのFreeプランを選び、下記の記事を参考にしてデプロイしました。

https://madogiwa0124.hatenablog.com/entry/2021/03/28/161255

今回作成するジョブについて

HerokuのFreeプランで運用しているアプリは、30分以上アクセスがないとスリープ状態になってしまいます。

アプリがスリープ状態になると、次にユーザーがアクセスした際の読み込みが非常に遅くなり、ユーザー体験を損ねてしまいます。

そこで、アプリへのアクセスを発生させるジョブを作成し、そのジョブを30分以内の間隔で定期的に実行するようにします。

まあ、HerokuのFreeプランは2022年11月に廃止されてしまうので、このジョブが活きるのもそこまでの話ではあるのですが……。

sidekiq-schedulerを導入する

sidekiq-schedulerはSidekiqの拡張gemで、cronのようにジョブを定期的に実行してくれます。GitHubはこちら。

https://github.com/sidekiq-scheduler/sidekiq-scheduler

このsidekiq-schedulerをRailsアプリに導入します。

Gemfile
gem 'sidekiq-scheduler'
$ bundle install

ジョブを作成する

下記のコマンドでジョブを作成します。

$ bundle exec rails g job access_route_page

生成されたファイルのperformメソッド内に、ジョブで実行したい処理を記述します。

app/jobs/access_route_page_job.rb
class AccessRoutePageJob < ApplicationJob
  queue_as :default

  def perform
    # 下記2行を追加
    uri = URI('あなたのアプリのURL')
    response = Net::HTTP.get_response(uri)
  end
end

作成したジョブは、[ジョブ名].perfom_nowですぐに実行できます。Redis、Sidekiqを立ち上げて、Railsのコンソール画面でジョブを実行してみましょう。

https://railsguides.jp/active_job_basics.html

https://qiita.com/jnchito/items/3482a30262874b80a8e4

$ redis-server
# 略
$ bundle exec sidekiq
# 略
$ bundle exec rails c
Loading development environment (Rails 7.0.3)
[1] pry(main)> AccessRoutePageJob.perform_now
Performing AccessRoutePageJob (Job ID: d5af5ea0-36fd-4598-a185-70c409400d43) from Sidekiq(default) enqueued at 
Performed AccessRoutePageJob (Job ID: d5af5ea0-36fd-4598-a185-70c409400d43) from Sidekiq(default) in 815.91ms
=> #<Net::HTTPOK 200 OK readbody=true>

無事HTTPリクエストが発生しました。

ジョブの実行スケジュールを追加する

最後に、作成したジョブを定期的に実行させましょう。

スケジュールを指定してジョブを実行させたい場合は、そのスケジュールをconfig/sidekiq.ymlに記述します。

例えば、下記の記述で、20分おきにAccessRoutePageJobが実行されます。

config/sidekiq.yml
:schedule:
  access_route_page:
    cron: '0 0/20 * * * *'
    class: AccessRoutePageJob

スケジュールの指定方法は、sidekiq-schedulerのREADMEで豊富に紹介されていますので、参考にしてみてください。

管理画面を追加する

上記までの内容を本番環境にデプロイすれば、やりたいことは終わりなのですが、Sidekiqでは便利な管理画面が用意されているので、ついでに追加しておきます。

管理画面を見られるユーザーは限定したいので、下記の記事を参考にBASIC認証を取り入れます。

https://zenn.dev/n04h/articles/sidekiq-auth

config/routes.rb
# 下記2行を追加
require 'sidekiq/web'
require 'sidekiq-scheduler/web'

Rails.application.routes.draw do
  # 下記4行を追加
  Sidekiq::Web.use(Rack::Auth::Basic) do |user_id, password|
    [user_id, password] == [ENV['USER_ID'], ENV['USER_PASSWORD']]
  end
  mount Sidekiq::Web, at: '/sidekiq'
end

ご自身でUSER_IDUSER_PASSWORDを指定し、環境変数に設定しましょう。

開発環境の場合、http://localhost:3000/sidekiqへアクセスすれば、Sidekiqの管理画面が見られます。

パスワードとIDの入力が求められるので、先ほど指定した、USER_IDUSER_PASSWORDを入力しましょう。

「定期ジョブ」のタブで、ジョブの実行状況が確認できます。

きちんと20分おきにジョブがスケジューリングされました!

感想

Herokuでcronライクなジョブ管理を実現する方法としては、今回紹介した方法のほかに、Heroku Schedulerというツールを利用する方法もあるそうです。

https://devcenter.heroku.com/ja/articles/scheduler

ここまで完全無料で遊ばせてもらっていたHerokuですが、Sidekiqとあわせて使っているRedisも11月から有料になったりするので、今後の身の振り方を考えねば・・・というところです。

Discussion