i'm interested in running a rails app with sidekiq, and without active job. i find that if active job is there, people get confused if they should use active job apis or sidekiqs, and i want to use sidekiq's apis exclusively for performance reasons.
does current versions of sidekiq (i.e. version 7) support active mailer without active job's deliver_later? i think the historical way to do this was through "delayed extensions" but i see now this has been removed in sidekiq 7:
Delayed extensions provide a very easy and simple way to make method calls asynchronous. By default, all class methods and ActionMailer deliveries can be performed asynchronously.
They were disabled in Sidekiq 5 and removed in Sidekiq 7.
https://github.com/mperham/sidekiq/wiki/Delayed-Extensions
so given that, is there a recommended way to use action mailer with sidekiq and without active job these days?
I am trying to schedule an email to be sent with a delay after an action is triggered. I'm using Action Mailer with the deliver_later functionality :
UserMailer.email_form(params[:session][:email]).deliver_later(wait: 2.minute)
It works fine locally and on heroku, except if I restart the server/deploy again while an email is scheduled but hasn't been sent. How do I get around this?
I think the problem is: deliver_later uses ActiveJob (a part/framework of Rails) under the hood to send emails in background. Rails by default comes with an async queue implementation that runs jobs with an in-process thread pool. Jobs will run asynchronously, but any jobs in the queue will be dropped upon restart or process crashes, because they are only in RAM (memory), but not in a persistent backend (DB, Redis).
You should switch to a different adapter (Sidekiq, Resque, Delayed Job, ...) if you want your jobs to be persisted.
You can find more details here.
I plan to send mails asynchronously in Rails 4.2.5 using ActionMailer#deliver_later.
The AppMailer file uses 'mail' to send across the mail & I am using deliver_later as follows:
AppMailer.project_created_support_mail(#project).deliver_later
However, logs show that the argument passed still is 'deliver_now'
[ActiveJob] [ActionMailer::DeliveryJob] [b341ea8c-ca96-4a4e-8079-572925864352] Performing ActionMailer::DeliveryJob from Inline(mailers) with arguments: "AppMailer", "project_created_support_mail", "deliver_now"
I am assuming there isn't an explicit need to attach a queue like Sidekiq or Resque.
Can someone please help in understanding what I am missing here?
EDIT: The original problem I am facing is that the action to send mail takes ~5 seconds with or without deliver_later. In an attempt to debug the issue, I found out that the argument is still 'deliver_now' (logs above). As pointed out by #torrocus below, 'deliver_now' is called inside the queue. However, the issue that deliver_later takes ~5 seconds still remains.
When you call #deliver_later method you put the job into the queue Active Job. Inside the queue it calls #deliver_now.
deliver_later (ActionMailer::MessageDelivery)
In development I propose to use gem mailcatcher
I am using Active_job and sidekiq to send emails asynchronously. But my current_locale is lost when performing the email sending. I set the I18n.locale by the url patterns of every request.
I used to use Sidekiq, which provide a plugin to store the current_locale, and use it when sending.
But I am now upgrading to Rails 4.2.1, ActiveJob seems it doesn't provide a solution like this.
Any thought?
One way I know is to pass the current_locale as an argument to mailer, then use I18n.with_locale {... }, but this would change many places...
I have an application that needs to occasionally send an email blast to the entire user base when an admin does something. This was working fine, but when there are a lot of users, the page for the admin will wait until all the mail is sent, which is undesirable.
To mitigate this, I tried sending email in a new thread:
t = Thread.new do
User.all.each do |user|
Mailer.email(user).deliver
end
end
at_exit{ t.join }
This worked fine, but then in my test suite, I can't test to ensure the email sending works:
# This test now fails with the new Thread above
test "admin action should send email blast" do
assert_difference("ActionMailer::Base.deliveries.count", User.count) do
post :action
end
end
So my questions are:
Is this method the best way to send email in a new Thread? Or is there a gem available that handles this kind of interaction?
How can I test that the emails are sent in my test suite if the sending is done in a new thread? Is there a way to check to wait for all threads to finish?
In rails 4.2 there's a special class that handles jobs called ActiveJob, active job allows you to queue long tasks for another process to handle them in the background, also you can queue tasks for a certain time, like for example "send this email tomorrow at 8 am".
For these queues to get handled you need to choose a backend to handle them, here's a list of backends that support ActiveJob
Each has it's pros and cons, sidekiq for example is a multithread handler, so it uses lower memory, while for example sucker punch uses the same thread as the main server, so it uses a lot less memory, suitable if you have a low memory server that can't handle a second ruby thread.
As for the testing part, rails guide already explains how to test your emails and test things like if emails has been queued or not, and test that the right template was rendered, and if it contains the right text.
I think you want to send mail asynchronously, For that you may use many gems like - delayed jobs, sidekiq etc. I would personally recommend to use sidekiq as its faster and used Redis in memory db behind the scene.
With Rails 4.2, Active jobs are introduced, so using it has advantage that you can switch from one queuing system to other without having any worry at any time and you can specify which queing machinery yiu want like
module YourApp
class Application < Rails::Application
# Be sure to have the adapter's gem in your Gemfile
# and follow the adapter's specific installation
# and deployment instructions.
config.active_job.queue_adapter = :sidekiq
end
end
I prefer using a queue based approach for async tasks. [Delayed job] (https://github.com/collectiveidea/delayed_job) is one option, but I prefer using [sidekiq] (http://sidekiq.org).
[Here] (http://blog.remarkablelabs.com/2013/01/using-sidekiq-to-send-emails-asynchronously) is an example of sending emails asynchronously using sidekiq.
Best way to send emails in separate threads is to use delayed jobs or similar gem.
https://github.com/collectiveidea/delayed_job
With delayed jobs gem, you can also send emails or do something else in different threads at scheduled time.
Another option is to use sidekiq, install sidekiq gem and add this line to application.rb file
config.active_job.queue_adapter = :sidekiq