Rakeタスクとwheneverを使用して、定期実行したい処理を回す方法
そもそもの定義
rakeタスクとは
Rake
とは:rubyで処理内容を定義できるビルドツールのこと。
Rakeタスク
とは:Rakeが実行する処理内容を「Rakeタスク」と呼ぶ。Rakeタスクを定義する場所を「Rakefile」と呼ぶ。
wheneverとは
whenever
とは:cronと呼ばれる、UNIX系のOSでは標準で備わってある仕組みを、rubyの簡単な文法で設定できるようにしたライブラリのこと。
cron
とは:「○時になったら○○のコマンドを実行」などといった具合に、定期的にコマンドを実行するためにメモリ場で常に命令を待機しているプロセス(=デーモンプロセス)のこと。
Rakeタスクの実装方法
1. Rakeタスクのファイルを作成
以下のコマンドを実行する
% rails g task <タスクの名前>
コマンドを実行することでlib/tasks/<タスクの名前>.rake
という新しいファイルが生成される。このファイルにRakeタスクを記入していく。
2. タスクに処理を記入する
今回は「「公開待ち」の記事に対して、公開日時が過去になっているものがあれば、状態を「公開」に変更する」といったRakeタスクを作成する。以下が実装したコードになる。
namespace :publish_article do desc "記事の公開日が過去の日時になったら、ステータスが「公開待ち」の記事を「公開」にする" task change_published: :environment do Article.where(status: :publish_wait).find_each do |article| if article.published_at <= Time.current article.update( state: :published ) end end end end
task change_published:
で区切られたブロック内にRakeタスクの内容を記述する。chenge_published:
の部分の名前は適切な名前に変更可能です。
:environment
の記述はデータベースに接続する場合必要になる。今回はArticleクラスのモデルに接続する必要があるので記載してある。
Articleモデルのスキーマ情報は以下の通り
# models/article.rb # == Schema Information # # id :bigint not null, primary key # author_id :bigint # uuid :string(255) # title :string(255) # description :text(65535) # body :text(65535) # state :integer default("draft"), not null # published_at :datetime # created_at :datetime not null # updated_at :datetime not null # deleted_at :datetime # # Indexes # # index_articles_on_author_id (author_id) # index_articles_on_deleted_at (deleted_at) # index_articles_on_published_at (published_at) # index_articles_on_uuid (uuid) # class Article < ApplicationRecord belongs_to :author enum state: { draft: 0, published: 1, publish_wait: 2 } end
3. 作成したRakeタスクが存在するか確認する
以下のコマンドを実行する
% bundle exec rake -T # 出力結果の中に2.で作成したRakeタスクの名前(今回だとchange_publishedの部分)が出力されているばOK ・・・ rake publish_article:change_published ・・・
4. Rakeタスクを実行する
% bundle exec rake publish_article:change_published
ログを確認してエラーが発生しておらず、Rakeタスクが実行されていればOK。
wheneverの使用方法
1. wheneverをインストールした後、以下のコマンドを実行する
# Gemfile gem 'whenever' => bundle installコマンドを実行
以下のコマンドを実行することで、config配下にschedule.rbというファイルが生成される。
% bundle exec wheneverize .
2. schedule.rbに設定と実行する処理内容を記載する
今回は「日付が変わる毎に先ほど記述したRakeタスクを実行する」ことにした。以下が実装したコードになる。
# Rails.rootを使用するために必要 require File.expand_path(File.dirname(__FILE__) + '/environment') # cronを実行する環境変数 rails_env = ENV['RAILS_ENV'] || :development # cronを実行する環境変数をセット set :environment, rails_env # cronのログの吐き出し場所 set :output, "#{Rails.root}/log/cron.log" every 1.day, at: '0:00' do rake 'publish_article:change_published' end
require
の部分はRails.rootを使用するためのコードです。
wheneverはRailsとは切り離されたもので単なるrubyのファイルとなっており、Railsとは関係のない単なるrubyのファイルの中でRailsのメソッドを使いたい場合、今回のような記述が必要となってきます。
rails_env
の部分はENV['RAILS_ENV']で環境を判断し、何も入っていなければ:developmentをrails_envに代入するようにしています。
処理内容の書き方については、今回は「Rakeタスクを毎日実行する」ようにしてあるのでrake
を使用しました。他の書き方については
runner "Rails内のメソッドを実行" command "bashコマンドを実行"
といったものがある。
3. crontabコマンドでcronを更新する
schedule.rbを変更しただけでは変更は反映されないので、以下のコマンドを実行することでcronにデータを反映させる。
% bundle exec whenever --update-crontab
次にcrontab -l
コマンドを実行して、先ほど反映させた定期実行タスクが存在するかを確認できる。
% crontab -l # Begin Whenever generated tasks for: (Rails_ROOT)/config/schedule.rb at: 2021-05-07 20:06:17 +0900 0 * * * * /bin/bash -l -c 'cd (Rails_ROOT) && RAILS_ENV=development bundle exec rake publish_article:change_published --silent >> (Rails_ROOT)/log/cron.log 2>&1' # End Whenever generated tasks for: (Rails_ROOT)/config/schedule.rb at: 2021-05-07 20:06:17 +0900