Rails Asynchonous Processing in the Model
My rails app has a simple model Links which tracks all the Urls associated with an Update.
class Link
include Mongoid::Document
include Mongoid::Timestamps
field :url, type: String
field :domain, type: String
attr_accessible :url, :domain
validates_uniqueness_of :url
has_and_belongs_to_many :updates
before_create :longenate
But before I create the object I'd like to get rid of any ur开发者_高级运维l shortening, for various reasons like longevity of link, and overall just not liking shorteners.
Currently my longenate function is very naive (still deving, so its supposed to be :) ), and creates quite a bottleneck since it blocks during the request, which can be quite a while if quite a few updates are being created at a time, and usually its a few dozen being created. As the Updates/Links and so forth need to be displayed back to the user quickly, this is a problem.
http_client = HTTPClient.new(:agent_name => "Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 6.0)")
begin
head_res = http_client.head(url)
unless head_res.header['Location'].empty?
short_url = url
self.url = head_res.header['Location'][0]
end
rescue Exception => e
self.domain = "ERROR ACCESSING URI"
self.url = "Error Accessing URI, site down/non existant?"
end
I would like to swap this out for something non blocking. I am familiar with eventmachine, and have used it to create some simple services and consumers, but am still relatively new to rails. What would be the best rails approach for something like this? A "finalize" function that includes an event machine loop to lengthen/create all the Links at one time, or maybe doing (somehow) within the model so that it spins off an async task whenever one is created?
Thanks for any advice/resources
There are a couple of background processing frameworks (delayedjob, stalker, resque, etc).... Arguably the easiest to get started with with Delayed Job.
Once you have delayedjob installed (gem install plus a migration), then you can do things like:
class Link
..
before_create :longenate
def longenate
# do your stuff
self.save
end
handle_asychronously :longenate
end
Then you have workers do their work using rake jobs:work
. This will take place in the background; with this implementation, you'll be saving records that have not been longenate'd, so you may want a 'status' field that tacks if it's been longenated or not.
More info: http://www.therailsway.com/2009/7/22/do-it-later-with-delayed-job
精彩评论