0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Docker環境でRailsのRakeタスクを作成し、バッチ処理のスケジュールを設定してみた

Last updated at Posted at 2024-12-29

バッチ処理とは

リアルタイムでの処理が難しかったり、一気に大量のデータを処理する場合に使用します。

また、毎日、毎週、または特定の時間帯に定期的に実行することも多いです。

具体的には

  • データベースのメンテナンス: 定期的なバックアップや不要なデータの削除
  • メール送信: 定期的に大量のメールを送信する処理
  • レポート生成: 大量のデータを集計してレポートを生成する
  • データ移行: 異なるシステム間でデータを移行する

などが挙げられます。

実行方法に関しては色々ありますが、今回はRakeタスクを作成とwheneverを使用して定期的にバッチ処理を実行するまでをやってみました。

開発環境

  • Rails 7.1.3
  • Ruby 3.3.3
  • Docker 24.0.7, build afdd53b

前提条件

今回はuser.rbに必要なカラムとメソッド等を用意しています。

user.rb
# id :bigint not null, primary key
# age(年齢) :integer
# birthday(誕生日) :date
# name(イニシャル) :string

# 本日誕生日のユーザーを絞り込む
scope :with_birthday_today, lambda {
  today = Time.zone.today
  where("EXTRACT(MONTH FROM birthday) = ? AND EXTRACT(DAY FROM birthday) = ?", today.month, today.day)
}

# 生年月日から年齢を計算してageにセットする
def set_age
  self.age = (Time.zone.today.year - birthday.year) - (Time.zone.today.month < birthday.month || (Time.zone.today.month == birthday.month && Time.zone.today.day < birthday.day) ? 1 : 0)
end

実装内容

ユーザー(User)の誕生日(birthday)当日に年齢(age)を更新するバッチ処理を作成。
毎日0:00に上記バッチ処理を実行するよう設定する。

Rakeタスクの作成

下記コマンドを実行することで、lib/tasks/user.rakeが作成されます。

$ docker-compose run web rails g task user

デフォルトでは以下のような記載がされています。

user.rake
namespace :user do
end

生成されたファイルを編集してみます。

user.rake
namespace :user do
  desc "今日が誕生日のユーザーの年齢を再計算して保存する"
  task update_age: :environment do
    # 本日誕生日のユーザーを取得
    users = User.with_birthday_today

    # 対象のユーザーが存在しない場合にログに出力
    Rails.logger.info puts "今日が誕生日のユーザーは存在しませんでした。" if users.blank?
    
    users.each do |user|
      # ユーザーの年齢を再計算してセットする
      user.set_age

      # 成功/失敗に関わらずログを出力
      if user.save
        Rails.logger.info puts "#{user.name}の年齢の更新に成功しました"
      else
        Rails.logger.error puts "年齢の更新に失敗しました"
      end
    end
  end
end

Rakeタスクを実行する

以下のコマンドで実行が出来ます。

# コマンド rails ファイル.定義したタスク名
$ docker-compose run web bundle exec rake user.update_age

定期的に実行するように設定する

今回は毎日0:00に実行するように設定していきます。

1. wheneverをインストール

wheneverというgemをGemfileに追加します。

Gemfile
gem 'whenever', require: false

Dockerコンテナ内でbundle installを実行して、wheneverをインストールします。

$ docker-compose run web bundle install

2. wheneverの設定

wheneverize .を実行して、config/schedule.rbファイルを生成します

$ docker-compose run web bundle exec wheneverize .

# 実行結果
[add] writing `./config/schedule.rb'
[done] wheneverized!

3. schedule.rb の編集

ログを保存するファイルを作成しておく(これは好み)

$ touch log/cron.log

config/schedule.rbに次のように記述して、毎日0:00にタスク user:update_ageを実行するように設定します。

schedule.rb
# 環境変数を cron ジョブに渡す(重要!)
ENV.each { |k, v| env(k, v) } 
# ログを保存
set :output, "log/cron.log"

every 1.day, at: '12:00 am' do
  rake 'user:update_age', environment: ENV['RAILS_ENV']
end

5. cronをインストール

Dockerイメージにcronをインストールします。

Dockerfileに以下を追加します。

&& apt-get install -y cron nano \

その後、イメージを再ビルドします。

$ docker-compose build

cronのインストール確認

docker compose run --rm --no-deps web which cron

# 実行結果
Starting periodic command scheduler: cron.
/usr/sbin/cron

6. cron関連の設定

entrypoint.shスクリプトを作成

$ touch entrypoint.sh

entrypoint.shを編集

entrypoint.sh
#!/bin/bash
set -e

# cronサービスを起動
service cron start

# Railsサーバーを起動
exec "$@"

コンテナ内でcronサービスを起動する設定を追加します。

Dockerfileに以下を追加して、cronを起動するスクリプトを作成します。

# entrypoint.sh スクリプトをコンテナ内の /usr/bin/entrypoint.sh にコピー
COPY entrypoint.sh /usr/bin/entrypoint.sh

# entrypoint.sh に実行権限を与える (実行可能なスクリプトにする)
RUN chmod +x /usr/bin/entrypoint.sh

# コンテナ起動時に実行するコマンドとして entrypoint.sh を指定
CMD ["/entrypoint.sh"]

docker-compose.ymlに追記

docker-compose.yml
services:
  web:
    # 追加
    entrypoint: ["/usr/bin/entrypoint.sh"]

cronがバックグラウンドで正しく起動しているか確認

$ docker-compose run web service cron status

# 実行結果
Starting periodic command scheduler: cron.
cron is running.

cronジョブの更新をする

$ docker-compose run web bundle exec whenever --update-crontab

# 実行結果
tarting periodic command scheduler: cron.
[write] crontab file updated

イメージを再ビルドします。

docker-compose build

現在登録されているcronジョブを確認

$ docker compose exec web crontab -l

# 実行結果
・
・
・
0 0 * * * /bin/bash -l -c 'cd /current_dir && RAILS_ENV=development bundle exec rake user:update_age --silent >> log/cron.log 2>&1'

# End Whenever generated tasks for: /current_dir/config/schedule.rb at: 2024-12-29 09:01:02 +0000

最後に

設定時間以降に

$ cat log/cron.log

を実行して、今回の場合であれば以下のログが残っていれば設定と動作が出来ています!

[ユーザー名]の年齢を[ユーザーの年齢]歳に更新しました"
or
今日が誕生日のユーザーは存在しませんでした。
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?