How to use multi-threading in rails 3?
Asked Answered
A

4

14

I am sending mail to the users using actionmailer through postmark. This is my code in controller:

@users = User.where(some condition)
@product = Product.find_by_name(some name).first
for user in @users
  UserMailer.new_product_arrival(user, @product, home_url).deliver
end

and this my user_mailer.rb

def new_product_arrival(user,product,home_url)
  @from         = Settings.mailer_from_address
  @recipients   = user.login
  @sent_on      = Time.now
  @user = user
  @product = product
  @content_type = "text/html"
  @home_url = home_url
end

The problem is that if there are more than 10 users it takes a very long time because of the for loop. I need to know if we can handle this by using multi-threading or background job. I don't want to use background job, but can anyone tell me how to implement the above using multi-threading.

I am using ruby 1.8.7 and rails 3.0.7

Audacity answered 22/11, 2011 at 16:38 Comment(1)
I'm not at all a ruby expert (yet) but postmark does support sending batch emails, so if you're emailing a large group of users, it might be easier for you to use that rather than an api call for each one.Capello
A
20

There basically two ways to wrap your loop in order to get "multi-threading":

  1. Spwan a thread for each delivery and join them back to the main thread

    threads = []
    for user in @users
       threads << Thread.new do
         UserMailer.new_product_arrival(user, @product, home_url).deliver
       end
    end
    threads.each(&:join)
    
  2. fork over the entire rails app ( pretty messy but the rails app serving the request will respond immediately ) and have the process detached:

    process = fork do
      for user in @users
        UserMailer.new_product_arrival(user, @product, home_url).deliver
      end
      Process.kill("HUP") 
      #sends the kill signal to current Process, which is the Rails App sending your emails 
    end
    Process.detach(process)
    

Hope that helps

Arteriole answered 22/11, 2011 at 17:35 Comment(2)
Will try this in my application.Audacity
When using threads you might want to add at the end of the Thread block: ActiveRecord::Base.connection.close (if the threads have DB calls, which they should have in your example).Altorelievo
S
1

our developer Artem recently made a major update to the Postmark gem

which allows you to send emails easily in batches, which should allow you to send emails faster. Check it out.

Sabbatarian answered 28/5, 2013 at 10:13 Comment(0)
M
0

Try delayed_job gem. This is a database-based background job gem. We used it in an e-commerce website, for example, sending order confirmation emails to users.

These tasks can happen asynchronously in the background, because your Rails app doesn't need them executed immediately.

Maestas answered 15/11, 2013 at 16:43 Comment(1)
"I don't want to use background job" -OPStickle
T
-4

um im a rails student from nairobi dev school kenya ..and i think you can give this a try ,..soo what you are having there is the delayed response due to the number of users ..you can try long polling an example

poll = function (){
  s.ajax{
       url:/'chat.json'
       data: { last_time: get last_time () }
     }}.done(function(data) {
     // handle data
     setTimeout(poll,1000);
     });
}

try that in your ow way ..this is useful for a real time application..o you can use even action controller:: live ..i think youre farmiliar with threading with rails .also .the above exmples will hep you ,,hopefuly \

Toole answered 28/11, 2013 at 6:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.