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
This is the initial thread of execution that began when the Ruby program was started. You can wait for a particular thread to finish by calling that thread's Thread. join method. The calling thread will block until the given thread is finished.
It's not a common production platform among the RoR community. As a result, Eventhough Rails itself is thread-safe since version 2.2, there isn't yet a good multi-threaded server for it on Windows servers. And you get the best results by running it on *nix servers using multi-process/single-threaded concurrency model.
The Ruby Interpreter is single threaded, which is to say that several of its methods are not thread safe. In the Rails world, this single-thread has mostly been pushed to the server.
The Ruby interpreter handles the management of the threads and only one or two native thread are created.
There basically two ways to wrap your loop in order to get "multi-threading":
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)
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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With