【问题标题】:DelayedJob causing variables in ActionMailer to be cached in production?DelayedJob 导致 ActionMailer 中的变量在生产中被缓存?
【发布时间】:2014-06-03 09:31:11
【问题描述】:

我们使用 Amazon SES 发送电子邮件,这就是为什么我们使用 DelayedJob 发送所有可能很庞大的电子邮件的原因。 DelayedJob 将这些电子邮件排队等待发送,它们之间至少间隔一秒钟。

它通常工作正常,但我发现变量似乎缓存在 ActionMailer 模板中以及与其中一些电子邮件一起发送的生成的 PDF 中。 PDF 是使用 Prawn 生成的。

例如,假设我们所有的客户都有一个唯一的 ID,我向两个客户发送了一封电子邮件。第一个客户端的 ID 为 1234,第二个客户端的 ID 为 2345。发生的情况是两个客户端都收到一封电子邮件,其中 ID 为 1234。两封电子邮件都发给了正确的人,并且其他一些变量将正确呈现。

我最初认为这个问题与我的电子邮件模板中使用了帮助程序有关。我将分享一个例子:

<%- @extra_lines.each do |line|
  if @interpolations
    @interpolations.each do |key,value|
      line = line.html_safe.sub "%{#{key}}", value.to_s
    end
  end %>
  <p><%= line.html_safe %></p>
<%- end %>

我希望这是有道理的,@extra_lines 是一个变量,它包含我们的电子邮件的一些额外段落,这些段落是基于一组条件生成的。 @interpolations 的每个成员的value 包含在第二封电子邮件中重复的内容。在上述情况下,@interpolations 看起来像 {user_id: 1234}

现在,并非所有变量都有这个问题。如果我只是渲染一个从 Mailer 类传递的变量,则不会发生这种情况。这就是为什么我担心我正在使用的一种辅助方法的输出被缓存的原因。更重要的是因为类似的行为发生在我的 PDF 类中。

所以我尝试通过生成一个启用了 DelayedJob 的新 Rails 应用程序来重现这一点,并创建了这个邮件:

class MyMailer < ActionMailer::Base
  default from: "from@example.com"

  def random_amount(arguments)
    @extra_lines = arguments[:extra_lines]
    @interpolations = arguments[:interpolations]
    mail to: 'to@example.com'
  end
end

此邮件模板:

<%- @extra_lines.each do |line|
  if @interpolations
    @interpolations.each do |key,value|
      line = line.html_safe.sub "%{#{key}}", value.to_s
    end
  end %>
  <p><%= line.html_safe %></p>
<%- end %>

还有这个控制器:

class RandomController < ApplicationController
  def index
    extra_lines = [
      'Test line 1',
      'Test line 2 with %{variable}',
      'Test line 3'
    ]
    10.times do
      interpolations = {variable: rand(1..100)}
      arguments = {extra_lines: extra_lines, interpolations: interpolations}
      MyMailer.delay.random_amount(arguments)
    end
    render :text => "Master, I've scheduled mail for you."
  end
end

这是尽可能接近“真实”应用程序的结果,它会导致向我发送 10 封具有唯一随机数量的电子邮件。因此,基本上,我无法重现该问题,而且更令人困惑的是,大部分时间它都能正常工作

有没有人听过这件事?

【问题讨论】:

  • 我在您的代码中注意到的第一件事是,在“邮件模板”中,您正在为@interpolations 执行每个循环,并将 line 设置为一个字符串。这意味着它只是循环中的最后一次迭代, vil 位于 line 变量中……这是设计使然吗?
  • 您能详细说明一下吗?在每次迭代中,line 变量通过用value 替换任何%{key} 匹配来更新。 @interpolations 中的每个键都是唯一的。
  • 只有= 每次迭代都会覆盖最后一次。因此,如果您想向您的 line 变量添加多个插值,您需要在 @interpolations.each 循环之前对其进行 decalere 并在循环内使用 line += .. 。否则 line 变量将只包含 @interpolations.each 的最后一次迭代的字符串
  • 也许我误解了你在说什么,但请注意line 变量已经设置,我没有做line = somethingelse,但实际上line = line.sub(..)。每个@interpolations.each 循环都会更新它。所以,最初它可以是Hello this is %{var1} and %{var2},在第一个循环之后它类似于Hello this is me and %{var2},将%{var1} 替换为me,在第二个循环之后它可能是Hello this is me and you
  • 啊。对不起这是我的错!在那里快速阅读代码:)

标签: ruby-on-rails-3 caching actionmailer delayed-job prawn


【解决方案1】:

我想我已经找到了问题的答案,而且比我最初想象的要简单得多。 @extra_lines 是从 I18n 数组构建的。我这样做是因为这些文本用于电子邮件、PDF 和网页中,并且因为它们是多语言的,所以我想将这些文本存储在一个中心位置,我觉得 I18n 是完美的,但它不支持数组插值,这意味着我必须自己滚动。

所以,长话短说,在 PDF 类中,我循环遍历生成的数组并使用 line.sub! "%{#{key}}", value.to_s(而不是 line = line.sub(..))进行插值,这也更新了 @extra_lines 变量,它更新了(缓存的) I18n.t('get.specific.extra.lines') 查询的结果。当它再次尝试对这些字符串进行插值时,它会在已经插值(缓存)的字符串上运行插值,因此不会发生插值。这就解释了为什么电子邮件在我的测试中运行良好:如果我在发送电子邮件之前生成了一个 PDF,它就会运行。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-09
    • 1970-01-01
    相关资源
    最近更新 更多