大ちゃんの駆け出し技術ブログ

RUNTEQ受講生のかわいいといわれるアウトプットブログ

【Rails】独自のRakeタスクの定期的実行

はじめに

こんにちは!大ちゃんの駆け出し技術ブログです。

先日にRakeタスクに関する記事を書きました。

sakitadaiki.hatenablog.com

記事ではデフォルトで実装されているRakeタスクの表示方法[ $ rake -T ]や、開発環境を表示するRakeタスク[ $ rake about ]の中身を実際に見てみました。

Rakeタスクの概要はざっくりと理解できたかなと思います。

このざっくりとした理解をより凝固なものにするために、今回は前回学んだRakeタスクを独自に作成する方法について発信します。

実際にRakeタスクを自分で実装することでより理解が深まると思います。

それでは本記事の内容に入っていきます。

※なお、今回使うアプリケーションは前回と同じファイルで行います(ファイル名が「scaffold_rake」とトピックが同じであるため)

Rakeタスクファイルの作成

それではRakeタスクファイルを作成してみます。

作成方法はシンプルで以下のようになります。

$ rails g task ファイル名

今回はファイル名をsample_taskとしてコマンドを実行しましょう。

$ rails g task sample_task
      create  lib/tasks/sample_task.rake

パス: lib/tasks/配下に新規ファイルが作成されました。

.rake とあるようにRakeファイルであることがわかります。

このように、Rakeタスクファイルはlib/tasks/配下に置かれていきます。

作成時のファイル状態は以下のようになります。

# lib/tasks/sample_task.rake
namespace :sample_task do
end

ここで簡単なRakeタスクの作成に入る前に、Rakeタスクファイルの構成について再度確認します。

name_space :ファイル名 do
    desc "Rakeタスクの処理内容の説明"
    task Rakeタスク名: :environment do
        処理内容(Rubyで記述)
    end
end

desc内にはタスクの説明を記述するんでしたよね。rake aboutなら "List versions of all Rails frameworks and the environment"といった具合ですね。

そしてその下にtaskを使ってRakeタスク名を定義します。

:environmentの記載は必須でしたね。

そしてdo~endのブロック内に実行したい処理をRubyで記述します。

それではsample_task.rake内に記載していきましょう。

実行する処理は「コンソールに"Hello"を出力する」ことにしましょう。

# lib/tasks/sample_task.rake
namespace :sample_task do
  desc "'Hello'をコンソールに出力"
    task output_hello: :environment do
        puts 'Hello'
    end
end

ここでrake -Tを使ってRakeタスク一覧をターミナル上に表示しましょう上で定義したRakeタスクが表示されると思います。

$ rake -T
・
・
rake restart                            # Restart app by touching tmp/restart.txt
rake sample_task:output_hello           # 'Hello'をコンソールに出力
rake secret                             # Generate a cryptographically secure secret key (this is typically used to generate a secret for cook...
・
・

実はタスクの実装自体も既に完了しております。

$ rake sample_task:output_helloを実行してみましょう。

$ rake sample_task:output_hello 
Hello

文字列「Hello」を出力できたかと思います。

Rakeタスクを簡単に実装できることが分かったのではないでしょうか。

cronとwhenever

独自のRakeタスクのことはある程度理解しましたが、用途についてはまだ説明していません。

色々とあると思いますが、今回はRUNTEQで学習した定期的に登録したRakeタスク(ジョブ)を実行する方法について発信します。

どのように定期タスクを登録するのかというとcronに登録します。

cronについて下記サイトでは以下のように説明しています。

cronとは、多くのUNIX系OSで標準的に利用される常駐プログラム(デーモン)の一種で、利用者の設定したスケジュールに従って指定されたプログラムを定期的に起動してくれるもの。

引用元: https://e-words.jp/w/cron.html

つまり UnixOS上にある定期的に何かのプログラムを自動で実行する設定のことを指します。

そして、このcronの設定にRakeタスクを登録するために使うgemがあります。それがwheneverです。

wheneverはRakeタスクがどれぐらいの頻度でどのRakeタスクを実行するかを設定することができます。つまり、wheneverで作成したファイルにRakeタスクを指定し、それをcronに登録するということです。cron上では頻度やRakeタスク自体の変更はできません。

Image from Gyazo

では実際にwheneverからインストールしていきましょう。

# Gemfile
gem 'whenever', require: false
$ bundle install
Fetching whenever 1.0.0
Installing whenever 1.0.0

wheneverを起動するために$ bundle exec wheneverize .をターミナル上で実行してください。

$ bundle exec wheneverize .
[add] writing `./config/schedule.rb'
[done] wheneverized!

するとconfig/配下にschedule.rbというファイルが作成されました。これが先ほど説明した、Rakeタスクがどれぐらいの頻度でどのRakeタスクを実行するかを記述するファイルになります。

中身を見てみましょう!!!

# Use this file to easily define all of your cron jobs.
#
# It's helpful, but not entirely necessary to understand cron before proceeding.
# http://en.wikipedia.org/wiki/Cron

# Example:
#
# set :output, "/path/to/my/cron_log.log"
#
# every 2.hours do
#   command "/usr/bin/some_great_command"
#   runner "MyModel.some_method"
#   rake "some:great:rake:task"
# end
#
# every 4.days do
#   runner "AnotherModel.prune_old_records"
# end

# Learn more: http://github.com/javan/whenever

全てコメントアウトされたファイルが作成されています。しかしながら、何を設定しているのかが見て理解できるファイル構造になっています。以下の箇所を参照して説明します。

# every 2.hours do
#   command "/usr/bin/some_great_command"
#   runner "MyModel.some_method"
#   rake "some:great:rake:task"
# end

every 2.hoursとありますが、これは言うまでもなくタスクの実行頻度でしょう。

そして、ブロック内にcommandrunnerrakeの3つのメソッドがあります。実はこのファイルでは、Rakeタスクだけ登録できると言うわけではなく、ターミナルのコマンドや定義されたメソッドも実行することができます。

  • command/usr/bin/some_great_commandからわかる通り、ターミナル上で実行するタスクを登録
  • runnerMyModel.some_methodからわかる通り、クラスメソッドを登録
  • rakesome:great:rake:taskからわかる通り、Rakeタスクを登録

今回使用するのはもちろんrakeです!

今回は先ほど作成したRakeタスクoutput_helloを毎時実行されるようにします。

# config/schedule.rb
every :hour do
  rake "sample_task:output_hello"
end

それではいよいよcronに登録してみましょう。

登録する前に、現在cronに登録されているタスクが何もないことを確認しましょう。cronに登録されているタスクを確認するためには、$ crontab -lをターミナル上で実行します。

$ crontab -l

何も表示されていないことを確認したら、次は以下のコマンドで設定ファイルをcronに反映します。

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

再度$ crontab -lをターミナル上で実行します。

$ crontab -l
# Begin Whenever generated tasks for: /Users/sakidendaiki/Downloads/RUNTEQ/for_blog/scaffold_rake/config/schedule.rb at: 2021-02-04 14:39:04 +0900
0 * * * * /bin/bash -l -c 'cd /Users/sakidendaiki/Downloads/RUNTEQ/for_blog/scaffold_rake && RAILS_ENV=production bundle exec rake sample_task:output_hello --silent'

# End Whenever generated tasks for: /Users/sakidendaiki/Downloads/RUNTEQ/for_blog/scaffold_rake/config/schedule.rb at: 2021-02-04 14:39:04 +0900

これで毎時登録したRakeタスクが実行されるようになりました。(サーバーが起動している時にのみ実行されます。つまり、$ rails sを実行してから1時間待つ必要がありますので、「Hello」をターミナル上で確認したい方は、1時間待つかww、設定ファイルを:hourから:minuteに変えて、再度cronに登録してください。)

終わりに

今回の内容はRUNTEQで学習したことの簡単なアウトプットです。 RUNTEQではもっと実用的な実装をしています。本当このスクールレベル高いなと思いながら毎日を生きています。

今回はただターミナル上に「Hello」を出力するだけのメソッドでしたが、本来であれば定期的にメールを送信するメソッドだったり、定期的にDBを更新するメソッドが使われます。 もしそんなメソッドを使う機会がアプリ作成時にあれば是非今回紹介した独自のRakeタスクの定期的実行方法を参考にしてみてください。

以上、大ちゃんの駆け出し技術ブログでした!