Wheneverを使ってRailsタスクを定期実行する
はじめに
Railsタスクでバッチ処理を動かしたいと思いました。
要するにcronでRailsタスクをコマンド実行したかったのですが、Railsを介するcrontabを簡単に設定・管理できる「Whenever」というgemがあるそうです。
というわけで、試してみたメモです。
環境
Ruby:2.4.1
Rails:5.1.1
Whenever:0.9.7
タスクを作る
Wheneverの話の前に、Railsでタスクを作ったことがなかったので、まずはタスク作りから始めます。
タスクファイルは何処にあるのか
cron(Whenever)的には、実行さえできればそれでよいので、必要なメソッドを備えたclassやmoduleが何処かにあれば良さそうです。
もっと言えば、「モデル内のクラスメソッドを定期的に実行したい!」というような場合、今回のように個別のタスクファイルは作成せずに、Wheneverで該当のクラスメソッドを記述してあげればよいのだと思います。
置き場所はlib/tasksが良さそう?
今回はアプリ内で完結する機能ではない想定なので、専用のタスクファイルを作成します。
https://altarf.net/computer/rails/2493
こちらの記事を参考に、lib/tasksに作成しました。
たとえば以下のようなファイル「lib/tasks/marimotask.rb」を作ります。
require "#{Rails.root}/app/models/marimodel" require "#{Rails.root}/app/lib/malib" class Tasks::Marimotask def self.marimo #modelやlibのメソッド呼んだり Marimodel.hoge Malib::Marimo.nyanya #適当な処理書いたり foo #putsしてみたり puts "成功しました!" end end
各modelやlibのクラスを使いたい場合は、個別にrequireしてあげる必要があるようです。
タスクのパスをオートロードにする
また、Wheneverからlib/tasksを呼び出せるようにパスも通してあげます。
config/application.rbに以下を追記します。
config.autoload_paths += Dir["#{config.root}/lib/**/"] config.eager_load_paths += Dir["#{config.root}/lib/**/"]
development環境ではconfig.autoload_paths、production環境ではconfig.eager_load_pathsが必要となります。(設定次第ですが)
当初私はconfig.autoload_pathsしか設定しておらず、とてもエラーに悩まされました。
この点は別途記事にしたいと思います。
手動実行してみる
$ bundle exec rails runner Tasks::Marimotask.marimo 成功しました!
これでタスクの準備ができました。
あとはWheneverを使って、このタスクをcrontabに登録していきます。
Wheneverの使い方
gemインストール
これは当然Gemfileに記述。
(略) gem "whenever"
Wheneverの設定ファイル作成
$ bundle exec wheneverize [add] writing `./config/schedule.rb' [done] wheneverized!
config/schedule.rbが作成されました。
これがcrontabの元になります。つまり、このファイルに「○時間ごとにxxを実行」みたいな処理を書いていきます。
schedule.rbの編集
先ほど作ったmarimoを登録したければ、以下のように書きます。
every 8.hours do runner "Tasks::Marimotask.marimo" end
これで8時間ごとにmarimoが実行されることを意味します。
以下のコマンドで、schedule.rbをcrontab用の記法に変換した結果を出力してくれます。
$ bundle exec whenever 0 0,8,16 * * * /bin/bash -l -c (略) ## [message] Above is your schedule file converted to cron syntax; your crontab file was not updated. ## [message] Run `whenever --help' for more options.
これはあくまでもscheduleの中身をcrontab用に翻訳してくれるだけで、まだcrontabに登録されたわけではありません。お試しです。
実際に反映するには次のコマンドを使います。
crontabへの反映
$ bundle exec whenever --update-crontab [write] crontab file updated
登録できた。ので、確認する。
あとはもういつものcrontabの話。
$ crontab -l # Begin Whenever generated tasks for: (Rails_ROOT)/config/schedule.rb 0 0,8,16 * * * /bin/bash -l -c (略) # End Whenever generated tasks for: (Rails_ROOT)/config/schedule.rb
できてた。
(補足と注意)wheneverコマンドのオプション
#schedule.rbをcrontabに反映(既存のcrontabは残る) $ bundle exec whenever --update-crontab #schedule.rbをcrontabに反映(既存のcrontabは消える!) $ bundle exec whenever --write-crontab #schedule.rbで定義したcrontabを削除 $ bundle exec whenever --clear-crontab
updateとwriteでは、whenever以外で定義したcronの扱いが異なります。
crontab中の#Begin〜から#End〜(Wheneverが書き込んだ範囲)のみを更新するのがupdateで、#Begin〜とか無視してcrontabをまるっと書き換えるのがwrite。
削除コマンドであるclearは、update同様に、BeginとEndで挟まれたWheneverによる定義部分のみを削除してくれます。