Hey everyone,
I''m still getting up to speed with Rails and Ruby. Is there a best
practice technique for kicking off a thread to work on an activity in
the background?
Here''s the scenario: the user performs an action that triggers e-mails
to be sent. (I''m using ActionMailer). My app acknowledges with a
message
to the user that the messages have been sent. I would like to show the
acknowledgment right away instead of the noticable delay I''m seeing now
depending on the number of recipients.
In my ActionController I do this:
<code>
def send_invites
...
thread = Thread.new(e) do |event|
EventMailer.send_invites(event)
end
thread.join ### this is what I''m curious about!
...
end
</code>
I''ve tested my code with Webrick and lighttpd on the Mac (Rails 1.1).
I''ve found that without the thread.join, the code doesn''t
work--the
EventMailer doesn''t get to do its work. From what I''ve read in
the
pickaxe book, I think it''s because the spawned thread is killed when
the
invoking (Rails) thread exits. The code works with the join, but this
defeats the purpose of what I''m trying to do as the UI thread blocks.
Am I taking the right approach here? Will my results be different under
Apache/FastCGI?
I came across DRb and Rinda when I did a quick search. Because I don''t
need to communicate with the background task, I''d prefer a really
simple
approach before I investigate DRb, Rinda or something else.
Thanks in advance for advice and feedback!
--Ed Lau
--
Posted via http://www.ruby-forum.com/.
Francois Beausoleil
2006-May-02 00:12 UTC
[Rails] Best way to do task in background in Rails
Hi ! 2006/5/1, Ed Lau <ted_spam@mac.com>:> <code> > def send_invites > ... > thread = Thread.new(e) do |event| > EventMailer.send_invites(event) > end > thread.join ### this is what I''m curious about! > ... > end > </code>Look into rails_cron or plain cron. In your controller, mark the event as ready to send, and then use a class method in Event to do the send: class Event def sent? self.sent_at end def send! return if self.sent? self.class.transaction do EventMailer.send_invites(self) self.sent_at = Time.now self.save! end end def self.send_ready self.find_ready.send! end end You can then run this code using script/runner: crontab -l * * * * * /u/me/apps/rails-app/script/runner -e production "Event.send_ready" Using rails_cron: class Event background :send_ready, :every => 1.minute end Hope that helps ! -- Fran?ois Beausoleil http://blog.teksol.info/