[Rails]Rails5 wheneverでRakeタスクを定期的に実行
Rakeとは
Rubyをインストールすると一緒にインストールされるrakeコマンドです。rubyで処理内容を定義するビルドツールです。
RakeコマンドとRakeタスクとは
rakeコマンドはmakeコマンド風にタスクを実行するためのタスクランナーで、実行する処理をRakeタスクと言います。また、定義する場所を「Rakefile」と呼びます。
簡単に言うと、Railsで定期的に実行したい処理をRubyコードでタスクとして定義しておき、必要なときに呼び出して実行することができる機能です。
特徴としてアプリケーションを起動せずにターミナル上で実行でき、サーバを起動せずに定義した処理を実行できます。
下記のようなときに使われます。
- データの連携
- データベースのバックアップ
- 定期的なデータの更新や削除など
Rakeタスクの使い方
Rakeタスクファイルの作成
railsにおいてrakeタスクファイルを作成するには下記のコマンドを実行します。
$ rails g task task_sample
実行すると、lib/tasks
以下のディレクトリにtask_sample.rake
というタスクファイルが生成されるので、このファイルに定義していきます。
※ rakeタスクを不適切なnamespaceへ追加しないようにします。
今回はメールに関するタスクなので、新たにディレクトリ分けします。
既存のタスクで関連するタスクがある場合は、同じnamespace
へ作成します。
rails g taske namespace(ディレクトリ名):新たに作成するRakeタスクファイル名
タスクファイルの記述
先程のコマンドによって作成されるタスクファイルは下記のようになっています。
lib/tasks/task_sample.rake
namespece :task_sample do
end
このブロック内に下記のように処理を記述していきます。
namespace :タスクのファイル名 do
desc '実行する処理の説明'
task :タスクの名前 do
実行する内容
end
end
具体例
lib/tasks/task_sample.rake
namespace :task_sample do
desc 'Hello, Rake Task'
task :hello do
puts 'Hello, Rake!'
end
end
DBに接続する場合
モデルにアクセスする場合は :environment
を付けます。
#モデルにアクセスする場合は :environment を指定します
namespace :task_sample do
desc 'Hello, Rake Task'
task hello: :environment do
puts 'Hello, Rake!'
end
end
作成したタスクの一覧
下記コマンドで作成したRakeファイルのタスクの名前と説明の一覧を取得できます。
$ bundle exec rake -T
rake hello # Hello, Rake Task
タスクの実行
タスクの実行は下記コマンドです。
$ bundle exec rake タスクのファイル名
$ rake hello
Hello, Rake!
wheneverで定期的な処理を行う
先程のような処理を定期的に実行するにはwheneverというgemを使います。
wheneverはcrontab管理ライブラリです。wheneverを使ってcronを動かします。
また、wheneverはバックグラウンドで処理されるものであるため、Railsとは関係のないプロセスである。
cronは.zshとrbenvの環境では動いてくれません!!
job_typeでPATHを通す必要があるので注意!
cronとは
UNIX系のOSに入っているプログラムの一つです。事前に「指定した時間に、指定したプログラム」を動かしてくれるものです。また、定期的にコマンドを実行するためにメモリ場で常に命令を待機しているプロセスです。
crontab(コマンド)とは
cronに指示するときに使うコマンドです。
wheneverのインストール
gem 'whenever', require: false
bundle install
アプリケーション側から使わないのでrequire: falseを付けます。これで、想定外の挙動を減らすことができます。
設定ファイルschedule.rbを作成
bundle exec wheneverize
これにより、config/schedule.rbファイルが作成されます(プロジェクト内にconfigフォルダが既に存在していればOK)。
wheneverの3つのジョブタイプ
Wheneverには、command
、runner
、rake
の3つのジョブタイプがあらかじめ定義されています。job_typeで独自のジョブタイプを定義することができます。
これらを使って実行させます。
rake
rakeタスク実行する
rake 'タスクのファイル名:タスク名'
command
bashコマンド実行
runner
Rails内のメソッド実行
job_typeで独自のジョブタイプを定義
例)
# .zshrcとrbenvのパスを指定するrakeを定義
job_type :rake, "source /Users/docha/.zshrc; export PATH=\"$HOME/.rbenv/bin:$PATH\"; eval \"$(rbenv init -)\"; cd :path && RAILS_ENV=:environment bundle exec rake :task :output"
# 毎日9:00に実行
every 1.day, at: '9:00 am' do
rake 'article_mailer:article_mailer'
end
schedule.rbの編集
cronは.zshとrbenvの環境では動いてくれません!!
job_typeでPATHを通す必要があるので注意!
例)config/schedule.rb
# whenever 定期実行
# rake 'ファイル名':タスク名'
# Rails.root(Railsメソッド)を使用するために必要
require File.expand_path(File.dirname(__FILE__) + '/environment')
# .zshrcとrbenvのパスを指定するrakeを定義
job_type :rake, "source /Users/docha/.zshrc; export PATH=\"$HOME/.rbenv/bin:$PATH\"; eval \"$(rbenv init -)\"; cd :path && RAILS_ENV=:environment bundle exec rake :task :output"
# cronを実行する環境変数(:development, :product, :test)
# 環境変数'RAILS_ENV'にセットされている変数またはdevelopmentを指定
# 自分の環境では'RAILS_ENV'はセットされていないのでnilです
rails_env = ENV['RAILS_ENV'] || :development
# cronを実行する環境変数をセット
# 今回はdevelopmentをセット
set :environment, rails_env
# cronのログの吐き出し場所
set :output, "#{Rails.root}/log/cron.log"
# 一時間毎に実行
every :hour do
rake 'article_state_check:article_state'
end
# 毎日9:00に実行
every 1.day, at: '9:00 am' do
rake 'article_mailer:article_mailer'
end
Example schedule.rb file
GitHub - javan/whenever: Cron jobs in Ruby
every 3.hours do # 1.minute 1.day 1.week 1.month 1.year もサポートしています。
# 以下のタスクは順番ではなく並行で実行されます
runner "MyModel.some_process"
rake "my:rake:task"
command "/usr/bin/my_great_command"
end
# 毎日 指定の時間
every 1.day, at: '4:30 am' do
runner "MyModel.task_to_run_at_four_thirty_in_the_morning"
end
# 毎日 指定の時間2回
every 1.day, at: ['4:30 am', '6:00 pm'] do
runner "Mymodel.task_to_run_in_two_times_every_day"
end
# 他にも次のショートカットがあります。 :hour, :day, :month, :year, :reboot
every :hour do
runner "SomeModel.ladeeda"
end
# 任意の曜日を選択または、 :weekend, :weekday
every :sunday, at: '12pm' do
runner "Task.do_something_great"
end
# 出力先logの指定
set :output, 'log/crontab.log'
# 実行環境の指定
set :environment, :development
設定内容にエラーがないか確認
これはあくまでもscheduleの中身をcrontab用に翻訳してくれるだけで、まだcrontabに登録されたわけではありません。
bundle exec whenever
cronにデータを反映
上記で設定した内容をcronに反映します。
bundle exec whenever --update-crontab
以上で完了です。
その他コマンド
現状のcrontabの記述内容の確認
crontab -l
現状のcrontabの記述内容の編集
crontab -e
cronからデータを削除
bundle exec whenever --clear-crontab
※ cronから強制削除(取り扱い注意)ディレクトリ名を変えたときなどは上記では消せないときに使用。
crontab -r
参考
エラー以外のログを出力する場合
Discussion