[Rails] Rakeタスク、cron、wheneverを使って一時間ごとにタスクを実行

学習記録

はじめに

Rakeタスクとは

Rakeとは、Rubyで人気のあるタスクランナーです。 タスクとは何か?

  • データベースのバックアップを作成する
  • テストの実行
  • 統計の収集と報告

Rakeによってタスクへのアクセスを一元化することができます。 Rakeを使用すると、特定のパターンに一致し、最近変更されたファイルを探すことなどが容易になります。

cronとは

多くのUNIX系OSで標準的に利用される常駐プログラムの一種で、利用者の設定したスケジュールに従って指定されたプログラムを定期的に起動してくれるものです。 このcronに対して命令を行うには、crontabを使います。

Rakeタスク

コマンドでlib/tasks配下にrakeファイルを作成します。

$ rails g task article_state

事前に公開日時が現在時刻から見て過去の記事を取得する為のscopeも作成しておきます。

scope :past_published, -> { where('published_at <= ?', Time.current) }

?はプレースホルダと呼ばれ、第二引数で指定した値が置き換えられます。 つまり、Time.currentで取得された現在の時間が?と置き換えれて、published_atの値と<で比較して検索します。

namespace :article_state do
  desc '公開待ちの中で、公開日時が過去になっているものがあれば、ステータスを「公開」に変更されるようにする'             # desc で処理の説明文を記入する
  task change_to_be_published: :environment do                                  # taskの名前を付ける。 environmentはDBへアクセスする場合に追記する。今回だとstateカラムの中身が変わるので必要。
    Article.publish_wait.past_published.find_each(&:published!)
  end
end

コードを紐解く

  • Article.publish_wait
    このようにenum のメソッドを使って、「公開待ち」であるデータを取得します。
  • find_each(&:published!)
    find_eachは全データをメモリに展開して処理するのではなく、決まった単位(デフォルト1,000件)ごとにデータをメモリに展開しつつ処理するメソッドです。
    &: はブロック内の省略記法です。以下のコードは同じ意味です。
Article.find_each(&:published!)
Article.find_each { |article| article.published! }

Rakeタスクの実行

Rakeタスクの一覧表示してみて、作成したタスクが登録されているか確認します。

> bundle exec rake --tasks
rake article_state:change_to_be_published  # 公開待ちの中で、公開日時が過去になっているものがあれば、ステータスを「公開」に変更されるようにする

実行コマンド

$ bundle exec rake article_state:change_to_be_published

wheneverの導入

cronをrubyの記法で簡単に扱えるようにしたgemライブラリです。

GitHubの公式に沿って導入していきましょう。

gem 'whenever', require: false

require: false: Railsの内部でwheneverを使うわけでは無いため、Railsの実行時に読み込まないようにするために付与しています。

$ bundle install

$ bundle exec wheneverize .            # configディレクトリ配下にあるschedule.rbファイルを作成

schedule.rb

# Rails.rootを使用
require File.expand_path(File.dirname(__FILE__) + "/environment")

# cronを実行する環境変数(RAILS_ENVが指定されていないときはdevelopmentを使用)
rails_env = ENV['RAILS_ENV'] || :development

# cronの実行環境を指定(上記で作成した変数を指定)
set :environment, rails_env

# cronのログファイルの出力先指定
set :output, "#{Rails.root}/log/cron.log"

# パスを通すコマンド
job_type :rake, "source /Users/[ユーザー名]/.zshrc; export PATH=\"$HOME/.rbenv/bin:$PATH\"; eval \"$(rbenv init -)\"; cd :path && RAILS_ENV=:environment bundle exec rake :task :output"

# 一時間毎に実行する&タスク名の指定
every :hour do
  rake 'article_state:change_to_be_published'
end

crontabを実行

crontabを使ってcronに対して命令をします。

$ bundle exec whenever --update-crontab   # wheneverの設定更新

$ bundle exec whenever  # 設定内容にエラーが無いか確認

$ crontab -l  # 設定されているcronを確認

$ bundle exec whenever --clear-crontab  # crontabの設定を削除

コメント

タイトルとURLをコピーしました