Ruby on Rails: How to run things in the background? - ruby-on-rails

When a new resource is created and it needs to do some lengthy processing before the resource is ready, how do I send that processing away into the background where it won't hold up the current request or other traffic to my web-app?
in my model:
class User < ActiveRecord::Base
after_save :background_check
protected
def background_check
# check through a list of 10000000000001 mil different
# databases that takes approx one hour :)
if( check_for_record_in_www( self.username ) )
# code that is run after the 1 hour process is finished.
user.update_attribute( :has_record )
end
end
end

You should definitely check out the following Railscasts:
http://railscasts.com/episodes/127-rake-in-background
http://railscasts.com/episodes/128-starling-and-workling
http://railscasts.com/episodes/129-custom-daemon
http://railscasts.com/episodes/366-sidekiq
They explain how to run background processes in Rails in every possible way (with or without a queue ...)

I've just been experimenting with the 'delayed_job' gem because it works with the Heroku hosting platform and it was ridiculously easy to setup!!
Add gem to Gemfile, bundle install, rails g delayed_job, rake db:migrate
Then start a queue handler with;
RAILS_ENV=production script/delayed_job start
Where you have a method call which is your lengthy process i.e
company.send_mail_to_all_users
you change it to;
company.delay.send_mail_to_all_users
Check the full docs on github: https://github.com/collectiveidea/delayed_job

Start a separate process, which is probably most easily done with system, prepending a 'nohup' and appending an '&' to the end of the command you pass it. (Make sure the command is just one string argument, not a list of arguments.)
There are several reasons you want to do it this way, rather than, say, trying to use threads:
Ruby's threads can be a bit tricky when it comes to doing I/O; you have to take care that some things you do don't cause the entire process to block.
If you run a program with a different name, it's easily identifiable in 'ps', so you don't accidently think it's a FastCGI back-end gone wild or something, and kill it.
Really, the process you start should be "deamonized," see the Daemonize class for help.

you ideally want to use an existing background job server, rather than writing your own. these will typically let you submit a job and give it a unique key; you can then use the key to periodically query the jobserver for the status of your job without blocking your webapp. here is a nice roundup of the various options out there.

I like to use backgroundrb, its nice it allows you to communicate to it during long processes. So you can have status updates in your rails app

I think spawn is a great way to fork your process, do some processing in background, and show user just some confirmation that this processing was started.

What about:
def background_check
exec("script/runner check_for_record_in_www.rb #{self.username}") if fork == nil
end
The program "check_for_record_in_www.rb" will then run in another process and will have access to ActiveRecord, being able to access the database.

Related

How to disable class cache for part of Rails application

I am developing a Rails app for network automation. Part of app consists logic to run operations, part are operations themselves. Operation is simply a ruby class that performs several commands for network device (router, switch etc).
Right now, operation is simply part of Rails app repo. But in order to make development process more agile, I would like to decouple app and operations. I would have 2 repos - one for app and one for operations. App deploy would follow standard procedure, but operation would sync every time something is pushed to master. And what is more important, I don't want to restart app after operations repo update.
So my question is:
How to exclude several classes (or namespaces) from being cashed in production Rails app - I mean every time I call this class it would be reread file from disk. What could be potential dangers of doing so?
Some code example:
# Example operation - I would like to add or modify such classes withou
class FooOperation < BaseOperation
def perform(host)
conn = new_connection(host) # method from BaseOperation
result = conn.execute("foo")
if result =~ /Error/
# retry, its known bug in device foo
conn.execute("foo")
else
conn.exit
return success # method from BaseOperation
end
end
end
# somewhere in admin panel I would do so:
o = Operations.create(name: "Foo", class_name: "Foo")
o.id # => 123 # for next example
# Ruby worker which actually runs an operation
class OperationWorker
def perform(operation_id, host)
operation = Operation.find(operation_id)
# here, everytime I load this I want ruby to search for implementation on filesystem, never cache
klass = operation.class_name.constantize
class.new(host).perform #
end
end
i think you have quite a misunderstanding about how ruby code loading and interpretation works!
the fact that rails reloads classes at development time is kind of a "hack" to let you iterate on the code while the server has already loaded, parsed and executed parts of your application.
in order to do so, it has to implement quite some magic to unload your code and reload parts of it on change.
so if you want to have up-to-date code when executing an "operation" you are probably best of by spawning a new process. this will guarantee that your new code is read and parsed properly when executed with a blank state.
another thing you can do is use load instead of require because it will actually re-read the source on subsequent requests. you have to keep in mind, that subsequent calls to load just add to the already existing code in the ruby VM. so you need to make sure that every change is compatible with the already loaded code.
this could be circumvented by some clever instance_eval tricks, but i'm not sure that is what you want...

Resque job not actually backgrounding

It is instead taking up my processor, and then effectually timing out.
I have in my controller :
after_save :handle_file
def handle_test
Resque.enqueue UnpackFileOnS3, parent.id
end
It hits this mark, and then the entire app waits for it to set up and upload the files as prescribed inside my Job. Then it predictably times out because it takes awhile to upload it.
This occurs in my console as well.. If I run :
Resque.enqueue UnpackFileOnS3, 4
Then instead of enqueue'ing it, it locks up my console as it tries to run the entire file. I think that normally, console would just enqueue it to a worker and redis..
Why isn't this actually happening in the background? As I assume if that were the case, the timeouts would not occur.
My guess is that you are running resque in an inline mode. In this mode queing is disabled. Check your configs for this kind of code:
Resque.inline = ENV['RAILS_ENV'] == "cucumber"
#or whatever, important part is the inline option

Rails and XMPP(Jabber) bot: advice about (asynchronous?) queue

So, i'm building a small application using Rails. I need to use XMPP proto for notification of users with a bit of commands to change user status.
Previous version was an application using plain Python(pretty ugly app) with plain SQL request into DB. There was a table "jabber_queue", so in separated script, bot was checking each second for any rows, processing it(sending message), deleting. It was simple and stupid, but it was ok.
Now i see, i need to integrate this bot functionality into Rails(at least to work with RSpec).
This is my few versions of how it can be done:
Use separated async queue solution. For example, Resque. Use separated Ruby script and push events into Resque, pop events in application(not dependent on DB, so easily fit with RSpec tests and test DB). But it makes my application a bit bloated - i need to use second DB with a lot of memory and CPU additional requirements - it will be overhead for my problem. Also, i don't want to support additional "thing" for this application, i know, it can be done a lot easier way.
Use delayed_job(queue solution using current AR DB). But i don't know how to get current AR DB of Rails application in separated script. Anyway, it's a dirty and ugly way.
Launch XMPP bot WITHIN Rails application, as background worker. So worker will get access to "current" AR(in case of testing, to test-DB). But i simply don't know how to do it. I've found a Navvy, but i need to put somewhere at Rails start a string like a "Navvy::Job.enqueue(Cow, :speak)", i don't know where will be best place for this, to start it with RSpec testing and "rails server". Also, there is a BackgrounDRb, but this project is similar to Navvy and inactive too. Using search on stackoverflow, i've found similar problem to mine, but solution leads me to background_job, which can just anything in background, but i still don't know how to get current AR DB access in separated script.
I'm so sorry for this amount of words in my problem, it's just a brainstream. I see some solutions, but i really need advices and some words from more experienced developers.
So, this was solved using yes, third way.
I've created a class for dealing with bot commands and AR models - awesomo.rb. Nothing special, really. I put this in /lib/ of Rails project. Secondly,
Created configuration file for easy setting of password and JID - config/awesomo.yml
development:
xmpp_jid: ...
xmpp_password: ...
I've created a daemon for my bot - awesomo_daemon.rb. Same, in /lib/. This is what it contains:
#preload rails environment
require File.expand_path(File.join(File.dirname(__FILE__),
'..', 'config', 'environment'))
#load xmpp bot class
require 'awesomo_daemon'
#load xmpp bot configuration file for current environment
AWESOMO_CONFIG = YAML.load_file(File.join(File.dirname(__FILE__),
'..', 'config', 'awesomo.yml'))[Rails.env]
#apply configuration before singleton will be initiated
Awesomo.setup AWESOMO_CONFIG['xmpp_jid'], AWESOMO_CONFIG['xmpp_password']
loop {
Awesomo.instance.idle
sleep 1
}
Created daemon script starter- script/awesomo.
#!/usr/bin/env ruby
require 'rubygems'
require 'daemons'
Daemons.run "lib/awesomo_daemon.rb", dir_mode: :normal,
dir: File.join(File.dirname(__FILE__), '..', 'tmp', 'pids')
Simply run it with command script/awesomo start.
And I can use any my models within awesomo.rb! Also, for queue, i'm using little model - XMPPJob with fields jtype(for example, "xmpp_message"), body("hey!"), to("john#jabber.com"). Fetching it within awesomo.rb idle function of bot class with limit(5).each do |job| case jtype ....
To post any new job for my "awesomo", i'm using function send_message:
def self.send_message to, body
xmppjob = XmppJob.new :jtype => "xmpp_message", :body => body, :to => to
xmppjob.save
end
Everything works perfectly, except XMPP library(xmpp4r-simple) itself, but I'll rewrite it soon using just xmpp4r.

How to run non blocking command from Ruby?

User goes to page A to create a new multiplayer game
The script in page A generates a unique ID for the game, and creates a worker for it. Something like: rails runner GameWorker.new(:game_id => game_id).start_game
The script in page A redirects the user to page B, where he can see the newly created game, and others can join.
The worker should be alive until the end of the game.
What would be the proper way to run the command that starts the worker? It must be non blocking and ideally redirect output to the log file, in case something goes wrong.
I'm using Rails 3, if it matters.
UPDATE
I'm gonna rephrase my question: How to run a linux command from within ruby and don't wait for the command to end? I mean the equivalent for &>>. In php for instance, &>> works fine and I don't need to use any special php functiont, but in ruby it seems to get overriden by and the script waits for the command to end and grab the output.
I HIGHLY recommend not running a process per game. If you want a non-blocking game that is not turn based, then you probably want to look at event-machine, or something like https://github.com/celluloid/celluloid-io
With either, you'll be creating threads that you'll process at future points in time.
But -- if you do want to just fire off a process in ruby, here you go.. from How to fire and forget a subprocess?
pid = Process.fork
if pid.nil? then
# In child
exec "whatever --take-very-long"
else
# In parent
Process.detach(pid)
end

Permanent daemon for quering a web resource

I have a rails 3 application and looked around in the internet for daemons but didnt found the right for me..
I want a daemon which fetches data permanently (exchange courses) from a web resource and saves it to the database..
like:
while true
Model.update_attribte(:course, http::get.new("asdasd").response)
end
I've only seen cron like jobs, but they only run after a specific time... I want it permanently, depending on how long it takes to end the query...
Do you understand what i mean?
The gem light-daemon I wrote should work very well in your case.
http://rubygems.org/gems/light-daemon
You can write your code in a class which has a perform method, use a queue system like this and at application startup enqueue the job with Resque.enqueue(Updater).
Obviously the job won't end until the application is stopped, personally I don't like that, but if this is the requirement.
For this reason if you need to execute other tasks you should configure more than one worker process and optionally more than one queue.
If you can edit your requirements and find a trigger for the update mechanism the same approach still works, you only have to remove the while true loop
Sample class needed:
Class Updater
#queue = :endless_queue
def self.perform
while true
Model.update_attribute(:course, http::get.new("asdasd").response)
end
end
end
Finaly i found a cool solution for my problem:
I use the god gem -> http://god.rubyforge.org/
with a bash script (link) for starting / stopping a simple rake task (with an infinite loop in it).
Now it works fine and i have even some monitoring with god running that ensures that the rake task runs ok.

Resources