问题
The common pattern for interfacing with ActionJob
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 ActionJob
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!
回答1:
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.
回答2:
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.
来源:https://stackoverflow.com/questions/32619366/difference-between-action-job-mailers-deliver-now-and-deliver-later