【Rails7】Rakeタスクをwheneverで定期的に実行する方法(タスクの自動化)

RailsにはRakeというgemが標準搭載されており、Railsで定期的に実行したい処理をRakeタスクとして定義しておくことで、必要なときに呼び出して実行することができます。

Rakeタスクを作成するメリットとしては、アプリケーションを起動せずにターミナル上で実行でき、サーバを起動していなくても定義した処理を実行できる点にあります。

そして、Rakeタスクをバックグラウンドで定期的に実行するためにはwheneverというgemを利用します。

Rakeタスクの処理を自動化したいなら、wheneverは是非とも導入しておきたい。

そこで、今回はRakeタスクをwheneverで定期的に実行する方法について覚書としてまとめました。

目次

開発環境

  • Ruby 3.1.2
  • Ruby on Rails 7.0.4
  • M1 Macbook Air 2020
  • mac OS Monterey (ver. 12.4)
  • ターミナル bash (Rosetta 2 使用

Rakeタスクの作成&実行

まずはRakeタスクの作成&実行を進めていきます。

ここでは例として、ActiveStorageでDBにアップロード済みのファイル(画像)の中から、モデルに紐付けされなかった不要ファイルを削除するタスクを作成していきます。

Rakeタスクファイルの作成

以下のコマンドを実行してlib/tasks以下にタスクファイルを作成します。

$ rails g task unattached_images

lib/tasks/unattached_images.rakeのように作成されていればOKです。

タスクファイルに処理内容を記述

lib/tasks/unattached_images.rakeに、以下のようにタスクの処理内容を記述します。

namespace :unattached_images do
  desc "紐付けされなかったアップロード(active_storage_blobs)を削除する"
  # タスク名(purge)を指定
  task purge: :environment do
    ActiveStorage::Blob.unattached.find_each(&:purge) # ←処理内容
  end
end

RakeタスクでActiveRecordを扱う場合、task:environmentオプションをつける必要があります(ActiveStorageがActiveRecordモデルにファイルを添付する機能を有しているため)。

タスクの実行

以下のコマンドでタスクを実行します。

$ rails unattached_images:purge

実際にタスクが実行できているか確認してみます。

Rakeタスク実行前のデータベース上のファイルは以下の通り。

Rakeタスクを実行すると、、

記述したタスクがちゃんと実行できていることが確認できました。

wheneverでRakeタスクを定期的に実行する

Rakeタスクの作成&実行ができたので、次はwheneverでRakeタスク処理を自動化していきます。

wheneverの導入

以下のように記述し、gemをインストールします。

gem "whenever", require: false
$ bundle install

設定ファイル(schedule.rb)の作成

以下のコマンドを実行すると設定ファイルconfig/schedule.rbが生成されます。

$ bundle exec wheneverize

設定ファイル(schedule.rb)の編集

設定ファイルconfig/schedule.rbを以下のように編集します。

require File.expand_path(File.dirname(__FILE__) + "/environment") # Rails.root(Railsメソッド)を使用するために必要
rails_env = ENV['RAILS_ENV'] || :development # cronを実行する環境変数(:development, :product, :test)
set :environment, rails_env # cronを実行する環境変数をセット
set :output, "#{Rails.root}/log/crontab.log" # cronのログ出力用ファイル

every 1.day do # タスクの実行間隔
  rake "unattached_images:purge" # ← rake "タスクのファイル名 : タスク名"
end

以下、タスクスケジュールのサンプルです。

・・・
# ------- スケジュールのサンプル --------
every :hour do # 1時間ごとに実行
  rake "unattached_images:purge"
end

every 1.day, at: '8:30 am' do # 毎日AM8:30に実行
  rake "unattached_images:purge"
end

every 1.day, at: ['8:30 am', '5:00 pm'] # 毎日2回、指定した時間に実行
  rake "unattached_images:purge"
end

every :sunday, at: '5:00 pm' do  # 指定した曜日、時間に実行
  rake "unattached_images:purge"
end

設定内容に間違いがないかチェック

設定ファイルの編集が終わったら、以下のコマンドを実行しエラーがないかチェックします。

問題なければ以下のような表示になるはずです。

$ bundle exec wheneverize
[skip] `./config/schedule.rb' already exists
[done] wheneverized!

cronにデータを反映&実行

最後に、cronにデータを反映かつ実行させるために以下のコマンドを実行します。

$ bundle exec whenever --update-crontab
[write] crontab file updated

これで、指定したスケジュールに沿ってRakeタスクが自動的に実行されるようになりました。

ちなみに、現状のcrontabの記述内容を確認する場合は以下のコマンドを実行します。

$ crontab -l
# Begin Whenever generated tasks for: /Users/xxxxxx/.../Railsアプリ/config/schedule.rb at: 2022-10-12 21:33:11 +0900
0 * * * * /bin/bash -l -c 'cd /Users/xxxxxx/.../Railsアプリ && RAILS_ENV=development bundle exec rake unattached_images:purge --silent >> /Users/xxxxxx/.../Railsアプリ/log/crontab.log 2>&1'

# End Whenever generated tasks for: /Users/xxxxxx/.../Railsアプリ/config/schedule.rb at: 2022-10-12 21:33:11 +0900

上記の/bin/bash -l -c 'cd ・・・ --silent'のコマンドを実行することでも、cronを実行させることができます。

$ /bin/bash -l -c 'cd /Users/xxxxxx/.../Railsアプリ && RAILS_ENV=development bundle exec rake unattached_images:purge --silent'

【Mac】”Operation not permitted – getcwd (Errno::EPERM)” が出た時の対処法

Macの場合、cronを実行しようとすると以下のようなエラーが出ることがあります。

(以下、log/crontab.logより一部抜粋)

cut: /Users/xxxxxxxx/……/.ruby-version: Operation not permitted
/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/rubygems/bundler_version_finder.rb:80:in `pwd’: Operation not permitted – getcwd (Errno::EPERM)

これは、Macにインストールされているcronへのアクセスが許可されていないために起こっていると考えられます。

そこで、Railsアプリケーションからcronにアクセスできるよう設定します。

Macのシステム環境設定の「セキュリティとプライバシー」を開き、

以下のように「ターミナル」と「cron」の項目にチェックを入れてアクセスを許可します。

僕の環境では上記画面上に「cron」が表示されていなかったので、「+」より追加しました。

cronアプリケーションの場所は以下のコマンドで調べられます。

$ which cron
/usr/sbin/cron

Command + Shift + . で隠しフォルダ、隠しファイルを表示できます)

アクセス許可をしたら、ターミナルを再起動してから以下のコマンドを実行してみます。

$ bundle exec whenever --update-crontab

これでcronが実行できるようになるはず。

(cronのタスク実行時にlog/crontab.logにエラーが吐き出されなければ成功です)

以上、参考になれば幸いです。

参考資料

Qiita
Railsでwheneverを使ってcronを設定する - Qiita 概要Railsでcronを管理するためのgem wheneverの使い方capistranoでwheneverをセットする方法gemインストールGemfileに追記# crongem '…
Qiita
【Mac】crontabでOperation not permittedと出た時の解決方法 - Qiita Macでcrontabを実行しようとすると以下のようなエラーが発生したので、エラー解決方法について記載します。$ crontabcrontab: tmp/tmp.9747: Operation …
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

愛知の34歳。無職で暇になり始めたプログラミング(Ruby on Rails)の忘備録をまとめたブログです。最近は別にやりたいことができたのでプログラミングほぼやっていません。気が向いたらまた再開するかも。僕の日常はメインブログの方で更新しています。

コメント

コメントする

目次