Digdagを用いてRubyOnRails環境でバッチ実装


Digdagについて

Getting started
Architecture
Concepts
Workflow definition
Scheduling workflow
Operators
Language API -Ruby
Digdagで環境毎に設定値を変える(RubyOnRails)
Digdagを用いてRubyOnRails環境でバッチ実装

準備

Ruby on Rails チュートリアルのサンプルアプリケーションダウンロード
https://github.com/yasslab/sample_app

Ruby on Rails チュートリアルのサンプルアプリケーションを実行して、ユーザーとPostを登録。
ぼくはtestユーザーを作って4つの投稿を登録しました。

今回は、ユーザー名をパラメーターにして該当するユーザーの投稿数を出力する簡単なバッチを作ります。
バッチの実装・起動は二つの方法でやってみます。

Railsでバッチ処理を書く際によく使われている以下の二つの方法をやってみます。
①rails runner:スクリプトとしてバッチを書く
■メリット
Rubyのスクリプトなので自由度が高い
■デメリット
Railsの環境を毎回読み込むので若干遅い
バッチの置き場所が決まってない

②rake task:ビルドタスクとしてバッチを書く
■メリット
namespaceメソッドを使ってグループ化ができる
taskの置く場所がきまっていて迷わない
■デメリット
処理の行数が長くなるとつらい
引数の渡し方に癖がある
一時的に使用するバッチの置き場所に困る

概要

Digdag: スケジュール、Alert、メインタスクだけ登録

rails runnerで実行

パラメーター取得はOptionParserを使いました。

バッチ処理スクリプトを追加

/lib/scripts/ の配下にバッチ処理スクリプトを追加

lib/scripts/post_batch.rb
require 'optparse'

module Scripts
  class PostBatch
    def initialize
      @option = {}
      OptionParser.new do |opt|
        opt.on('-n VALUE', 'user name') { |v| @option[:name] = v}
        opt.parse!(ARGV)
      end
    end

    def count
      user = User.find_by(name: @option[:name])
      puts "ID: #{user.id} 名前: #{user.name}"
      puts "投稿数: #{Micropost.where(user_id: user.id).count}"
    end
  end
end

lib配下のrubyファイルを自動ロードする

config/application.rb
config.autoload_paths += %W(#{config.root}/lib)

workflowsの配下にrails_runner.digを追加して以下の内容を追加

rails_runner.dig
+task:
  sh>: bundle exe rails runner Scripts::PostBatch.new.count -n 'test'

実行

testユーザーのID,名前、投稿数が出力されています。

実行結果
$ digdag run rails_runner.dig --rerun
2020-07-20 19:38:39 +0900 [INFO] (0017@[0:default]+rails_runner+task): sh>: bundle exec rails runner Scripts::PostBatch.count 'test'
ID: 5 名前: test
投稿数: 4

rakeで実行

rakeタスク生成

$ rails g task task_post
Running via Spring preloader in process 4255
      create  lib/tasks/tast_post.rake

/lib/tasks/task_post.rake ファイルが生成されるので開いて以下のソースを追加

lib/tasks/task_post.rake
namespace :task_post do
  desc "ユーザー投稿数を取得"
  task :count, ['name'] => :environment do |task, args|
    user = User.find_by(name: args.name)
    puts "ID: #{user.id} 名前: #{args.name}"
    puts "投稿数: #{Micropost.where(user_id: user.id).count}"
  end
end

Workflow追加

rake.dig
+task:
  sh>: bundle exec rake task_post:count[test4]

実行

testユーザーのID,名前、投稿数が出力されています。

実行結果
$ digdag run rake.dig --rerun
2020-07-20 20:04:16 +0900 [INFO] (0017@[0:default]+rake+task): sh>: bundle exec rake task_post:count[test]
ID: 5 名前: test
投稿数: 4