Action Job/Mailer 的 `deliver_now` 和 `deliver_later` 之间的区别
Posted
技术标签:
【中文标题】Action Job/Mailer 的 `deliver_now` 和 `deliver_later` 之间的区别【英文标题】:Difference between Action Job/Mailer's `deliver_now` and `deliver_later` 【发布时间】:2015-12-13 16:12:54 【问题描述】:Rails 中与ActiveJob
交互的常见模式是使用perform()
方法设置一个作业,该方法通过perform_now
或perform_later
异步调用
在Mailers的特殊情况下,您可以直接调用deliver_now
或deliver_later
,因为ActiveJob
与ActionMailer
很好地集成。
rails documentation 有以下 cmets -
# 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
措辞使deliver_now
看起来不会使用ActiveJob
发送邮件。这是正确的,如果是这样,deliver_now
和deliver_later
之间的真正区别是什么?一个不是异步的吗?
同样,perform_now
和 perform_later
也有同样的区别吗?
谢谢!
【问题讨论】:
对我来说,ActionMailer 和 ActionJob 像这样相互混淆似乎很糟糕。 ActionJob 应该不知道工作正在做什么。 ActionMailer 应该能够被 ActionJob 延迟,而不必知道它正在被延迟,就像任何其他对象一样。对我来说,这似乎在 Rails 3、4 和 5 中被打破了。 【参考方案1】:正如您在问题中所说,deliver_now
不使用ActiveJob
。
基本上,deliver_later
是异步的。当您使用此方法时,电子邮件不会在此刻发送,而是被推送到作业队列中。如果作业未运行,则不会发送电子邮件。 deliver_now
将在此时发送电子邮件,无论工作的状态如何。 Here 你可以查看deliver
方法的文档。
根据您的第二个问题,perform_now
将立即处理作业而不发送到队列。但是,perform_later
会将作业添加到队列中,并且一旦作业的队列空闲,就会执行作业。 Here 你可以查看perform
方法的文档。
【讨论】:
浏览器连接关闭了怎么办?还会执行 Deliver_later 吗? @gatesdeliver_later
在服务器端进行管理,因此浏览器连接是否关闭无关紧要。一旦作业被推送到队列中,它就会被发送(除非你终止作业进程)。
我想知道如果从脚本调用,通过'rails runner bin/send-lots-of-email.rb'执行,行为会发生什么变化?【参考方案2】:
除了 Daniel Batalla 所写的内容之外,我还做了一个观察:deliver_later
似乎执行惰性求值,而 deliver_now
没有。
我有一个 ActiveRecord 模型,它带有一个未存储在数据库中的附加属性 reset_token
(来自 Michael Hartl 的 railstutorial.org;该模型将令牌的哈希版本存储在 reset_digest
列中)。
执行deliver_now
时,访问邮件视图中@model
的reset_token
属性会按预期生成重置令牌。但是,在执行deliver_later
时,@model.reset_token
始终是nil
。似乎deliver_later
使用数据库数据更新了模型,并且因为reset_token
是一个不受数据库支持的附加属性,所以此时它将是nil
。 (代码文档嵌套太深,我无法在源代码中验证这一点。)
Michael 在教程中使用deliver_now
。我不知道他这样做是为了避免懒惰的评估。但我花了一段时间才意识到我只需将 deliver_later
更改为 deliver_now
即可通过测试。
【讨论】:
由于deliver_later
是异步的,因此需要重新加载对象。就像任何异步作业一样。因为需要对工作进行新的更改(如果有)。
谢谢你,@bovender。我只是有同样的问题。在我的模型中,有几种方法可以计算总价/总价,如果我按如下方式运行邮件程序Mailer.payment_email(model, calculate_price).deliver_later
,price
始终是nil
。使用deliver_now
会有所帮助,但它会破坏异步交付的所有好处。为了克服它,我用calculate_price.to_f
替换了calculate_price
,它强制进行方法评估。在其他情况下,它可能是to_i
、to_s
等,具体取决于方法返回的数据类型。以上是关于Action Job/Mailer 的 `deliver_now` 和 `deliver_later` 之间的区别的主要内容,如果未能解决你的问题,请参考以下文章