Does system "...&" still work on Heroku Cedar / Rails 3.1?
I have a couple of rake tasks run in the background using RyanB's technique from Railscast 127, which work fine locally and on Rails 3, but not on 3.1 in production on Heroku's cedar stack. Before I rip them out and replace them with delayed_job, should this method of forking a process still work?
def call_rake(task, options = {})
options[:rails_env] ||= Rails开发者_JAVA技巧.env
args = options.map { |n, v| "#{n.to_s.upcase}='#{v}'" }
system "rake #{task} #{args.join(' ')} --trace 2>&1 >> #{Rails.root}/log/rake.log &"
end
Answering this myself, after digging around: the system bit does but not the &. Delayed_job is the way to go on this. FWIW here's my working code to run a rake task in a rails 3.1 app using delayed_job on Heroku's Cedar stack, to generate an XML file, save it to temp then upload to S3. The XML output file is large, hence the need to handle it asynchronously.
app/classes/callrake.rb:
class Callrake
def call_rake(task, options = {})
options[:rails_env] ||= Rails.env
args = options.map { |n, v| "#{n.to_s.upcase}='#{v}'" }
system "rake #{task} #{args.join(' ')} --trace 2>&1 >> #{Rails.root}/log/rake.log"
end
handle_asynchronously :call_rake
end
isbns controller:
def onixtwo
#using Ransack, successor to Metasearch
@q = Isbn.where(:client_id => current_user.client_id).search(params[:q])
@isbns = @q.result(:distinct => true)
if @q.nil?
@isbns = Isbn.where(:client_id => current_user.client_id)
end
#I have an array to pass so this is a bit hacky - make an array, pass it as a string then turn it back into an array using eval()
is = []
@isbns_to_pass = @isbns.each {|isbn| is << isbn.id }
@client = current_user.client_id
@user = current_user.id
callrake = Callrake.new
callrake.call_rake(:onixtwo, :isbns => is, :client => @client, :user => @user)
redirect_to isbns_path, :flash => { :notice => t(:isbnonixtwo).html_safe }
end
slightly off-topic config/locales/en.yml for completeness:
en:
isbnonixtwo: "Onix 2.1 message is generating. When it's done, you can download it from the <a href='/onixarchives'>Onix Archive</a> list."
rake task:
desc "Generate an onix 2.1 xml file"
task :onixtwo => :environment do |t|
client_id = ENV["CLIENT"]
user_id = ENV["USER"]
isbns_passed = ENV["ISBNS"]
isbnsarray = eval(isbns_passed)
filename = "#{Rails.root}/public/#{Client.find_by_id(client_id).client_name}-#{Date.today}-#{Time.now}-onix-21.xml"
isbns = Isbn.find_all_by_id(isbnsarray)
File.open(filename, "w") do |file|
xml = Builder::XmlMarkup.new(:target => file, :indent => 2)
xml.instruct!(:xml, :version => "1.0", :encoding => "utf-8")
xml.declare! :DOCTYPE, :ONIXMessage, :SYSTEM, "http://www.editeur.org/onix/2.1/03/reference/onix-international.dtd"
xml.ONIXMessage do
xml.Header do
#masses of code
end #of file
xmlfile = File.open(filename, "r")
onx = Onixarchive.new(:client_id => client_id, :user_id => user_id)
onx.xml = xmlfile
onx.save!
end #of task
Then Onixarchive has a regular paperclip attachment set-up in the model.
Note the Rails.root.public in the filepath - I kept getting a "does not exist" when I tried to write to app/tmp, because, sure enough when I looked using heroku's console, there is no tmp folder. I suppose I could have created one, but this app is on cedar, which has an ephemeral filesystem so you can write anywhere for the duration of the session.
精彩评论