ruby script/runnerのお話
以前ruby script/runner関連で意味不明なエラーが出たのでちょっと調べてみました。
今の自分にはわからないことが多かったので、雑多にまとめてみようと思います。
「RailsアプリでActiveRecordを使ったバッチ処理 その2」
http://higelog.brassworks.jp/?p=12
- ruby on railsではscript/runnerを使えばWebアプリ内からではなくてもメソッドを実行することができる
- script/runnerはRails環境を読み込んだうえでワンライナーを実行するためのスクリプト
- このコマンドをcronなどで定期的に実行するようにする
「script/console と script/runner の環境の指定方法の違い」
http://d.hatena.ne.jp/takihiro/20080507/1210163583
script/console と script/runner で環境の指定の仕方が違うとのこと。
% ruby script/runner -e production % ruby script/console production
使い方のヘルプはそれぞれこんな感じ。
% ruby script/runner -h Usage: script/runner [options] ('Some.ruby(code)' or a filename) -e, --environment=name ...
% ruby script/console --help Usage: console [environment] [options]
環境を設定するコードも全然違うみたい。
- rails-2.3.14/lib/commands/runner.rb
require 'optparse' options = { :environment => (ENV['RAILS_ENV'] || "development").dup } code_or_file = nil ARGV.clone.options do |opts| opts.on("-e", "--environment=name", String, "Specifies the environment for the runner to operate under (test/development/production).", "Default: development") { |v| options[:environment] = v } end ENV["RAILS_ENV"] = options[:environment] RAILS_ENV.replace(options[:environment]) if defined?(RAILS_ENV)
- rails-2.3.14/lib/commands/console.rb
ENV['RAILS_ENV'] = case ARGV.first # (1) when "p": "production" when "d": "development" when "t": "test" else ARGV.first || ENV['RAILS_ENV'] || 'development' end
Rails task: script/runner or rake? - Stack Overflow
http://stackoverflow.com/questions/591503/rails-task-script-runner-or-rake
scrpt/runner some_useful_thing と rake some:other_useful_thingどちらが好まれるかという話。
script/runner がRailsを呼び出すのに対し、 rakeは :environment を指定したりして呼び出すことを明確にしない限りRailsを呼び出さない。
Railsを呼び出すのはコストがかかるので、避けられるに越したことはないという話になります。
とは言ってもほとんど同じとのこと。どちらも使うことはあるし、むしろ script/runner を使う人もいるようです。
script/runner OR script/rails runnerがクソ重い。どうしてくれんのよ?
http://d.hatena.ne.jp/babie/20100506/1273157249
Railsでのバッチ処理(script/runner)は環境を全部ロードするのでスタートアップがとても重いとのこと。
daemon_generatorなどを使う手もある。
他にもたくさん方法はあるみたいです。
- RailsアプリでActiveRecordを使ったバッチ処理 その3
http://higelog.brassworks.jp/?p=15
でもちょっと大げさ、というときのための手軽な方法があるようです。
actionに処理内容を書いて、ローカルのスクリプトからHTTPアクセスして叩く、という方法。
手動やcron/crontabで処理しようと思っていたなら使える方法です。
- app/controllers/hoge_controller.rb
class HogeController < ActionController::Base def batch # IP制限しないと怖いですよ…… raise NotFoundError.new unless request.remote_ip == "127.0.0.1" # 処理内容を書く ... render :text => "ok", :status => 200 end end
IPアドレスを制限するのがポイントとのこと。
じゃあバッチスクリプトはどう書くかというと、
- script/batch.rb
#!/usr/bin/env ruby require "net/http" Net::HTTP.version_1_2 if __FILE__ == $0 Net::HTTP.start('127.0.0.1', 80) do |http| response = http.get("/hoge/batch") unless response == Net::HTTPSuccess # log にエラーを吐くとか……適当に。 end end end
こんな感じで、cron/crontabに設定しておけばよいようです。
NotFoundErrorのところ、ちゃんと定義しておく必要がある(名前は任意)みたい。
- app/controllers/application_controller.rb
class ApplicationController < ActionController::Base ... class NotFoundError < StandardError; end rescue_from NotFoundError, :with => :record_not_found def record_not_found render :file => File.join(RAILS_ROOT, 'public', '404.html'), :status => 404 end end
すでにロードされているので激速とのこと。今度試してみる。