Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between Action Job/Mailer's `deliver_now` and `deliver_later`

The common pattern for interfacing with ActiveJob in Rails is to set up a Job with a perform() method that gets called asynchronously via perform_now or perform_later

In the special case of Mailers, you can directly call deliver_now or deliver_later since ActiveJob is well integrated with ActionMailer.

The rails documentation has the following comments -

# If you want to send the email now use #deliver_now
UserMailer.welcome(@user).deliver_now
 
# If you want to send the email through Active Job use #deliver_later
UserMailer.welcome(@user).deliver_later

The wording makes it seem like deliver_now will not use ActiveJob to send the mail. Is that correct, and if so what's the true difference between deliver_now and deliver_later? Is one not asynchronous?

Similarly, does the same difference apply to perform_now and perform_later ?

Thanks!

like image 564
user2490003 Avatar asked Sep 16 '15 21:09

user2490003


2 Answers

As you say in your question, deliver_now does not use ActiveJob.

Basically, deliver_later is asynchronous. When you use this method, the email is not send at the moment, but rather is pushed in a job's queue. If the job is not running, the email will not be sent. deliver_now will send the email at the moment, no matter what is the job's state. Here you can see the documentation for deliver methods.

According to your second question, perform_now will process the job immediately without sending to the queue. perform_later, however, will add the job to the queue, and as soon the job's queue is free, will perform the job. Here you can see the documentation for perform methods.

like image 58
Daniel Batalla Avatar answered Oct 17 '22 22:10

Daniel Batalla


In addition to what Daniel Batalla wrote, here's one more observation that I made: deliver_later seems to perform lazy evaluation, while deliver_now does not.

I have an ActiveRecord model with an additional attribute reset_token that is not stored in the database (this is from Michael Hartl's railstutorial.org; the model stores a hashed version of the token in the reset_digest column).

When executing deliver_now, accessing the @model's reset_token attribute inside the mailer view yields the reset token as expected. However, when executing deliver_later, @model.reset_token is always nil. It appears as if deliver_later updates the model with database data, and because reset_token is an additional attribute that is not backed by the database, it will be nil at that point. (The code documentation is too deeply nested for me to be able to verify this in the source.)

Michael uses deliver_now in the tutorial. I don't know he does this to avoid lazy evaluation. But it took me a while to realize that I just had to change deliver_later to deliver_now to make my tests pass.

like image 39
bovender Avatar answered Oct 17 '22 21:10

bovender