如何监控ActionMailer的deliver_later状态

3

简述

如何跟踪由deliver_later入队的邮件以及它们的投递状态?

详情

我想使用Action Mailer中的deliver_later异步发送一堆电子邮件。这个功能可以正常工作,通过使用wait:参数可以使邮件异步发送。到目前为止都很好。

现在我想提供一些关于已发送邮件状态的信息。例如一个简单的字符串,如x/y mails sent,我之后可以通过http或其他方式查询(这不是本问题的关注点!)。我的期望是可以轻松访问工作队列或类似的东西,然后像after_action回调那样注册一个回调函数,但显然没有这样的机制,看起来我需要手工编写这些回调函数,但我找不到任何一个资源甚至提到“投递状态”的主题。看起来似乎世界上没有人关心deliver_later的邮件是何时被发送的?我所能找到的最接近的事情是如何为了单元测试目的检查此状态,但这绝对不是我想要的。

1个回答

3

除了您选择的后台作业系统之外,没有数据存储库可以存储有关异步传递的完整性或状态的信息。但是,您可以使用Rails Observer模式观察邮件的传递。如果您想跟踪邮件传递的尝试和状态,我建议为每个传递添加一个数据库表。

跟踪调用邮件程序方法以创建传递:

您可以在邮件程序中添加before_action,为被调用的邮件消息编写数据库记录。在此处为您的消息添加UUID,以便稍后在数据库中找到它。 UUID可以添加到您的消息头中。

跟踪邮件程序传递消息(稍后):

您可以使用register_observer将观察者添加到邮件程序(或所有邮件程序)。观察者类必须实现self.delivered_email(message),并且该方法将在发送电子邮件后调用。此时,您可以找到数据库记录并在其上写入时间戳以将其标记为“已发送”。

以下是可能看起来像的示例:

这是未经测试的代码,可能无法按原样工作

# your mailer class
class NotifierMailer < ApplicationMailer
  after_action :record_delivery

  private

  def record_delivery
    # create an identifier for this mail message and add it 
    # to the headers of the mail message
    headers['X-Delivery-Id'] = SecureRandom.uuid
    # write a database record to track that this email is to be sent
    MailDelivery.create(uuid: headers['X-Delivery-Id'])
  end
end

# an observer class
class MailDeliveryObserver
  def self.delivered_email(message)
    delivery = MailDelivery.find_by(uuid: message.header['X-Delivery-Id'])
    delivery&.touch(:sent_at)
  end
end

# in application.rb
# NotifierMailer can be any mailer
NotifierMailer.register_observer(MailDeliveryObserver)

这里有一篇关于观察者模式的文章

这些是当前Rails文档中关于观察者的部分


我的意思是delivered_email是一个观察者的钩子,用于判断"邮件是否成功发送",但一旦你告诉后台作业去执行(deliver_later),你就必须以分布式方式存储这个"工作"单元。根据你的电子邮件服务提供商,通常你也可以在邮件送达时从ESP接收到webhooks。我不认为Amazon SES会这样做。否则,发送邮件的后台作业必须将"成功发送"写入分布式存储中。 - undefined
1
除此之外,这个解决方案有点过度工程化。我可以看到日志中由activejob生成的“作业ID”。我还能看到与“作业ID”匹配的“执行中”和“已执行”的日志消息。不必依赖数据库,应该可以设计一些简单的内存观察者来处理这个问题。 - undefined
id必须作为参数传递给调用动作邮件方法的语句,例如ActionMailer.with(delivery_id: SecureRandom.uuid)。这样,随后创建的每个Mail对象都将获得相同的id作为参数传递。通过这种方式,消息可以在delivered_mail中被传送。如果在其他情况下对邮件对象进行操作,将会生成多个ID,而无法确定哪一个是指向重复对象的。 - undefined
1
FYI:在观察者中,正确的对象是 message.header['X-Delivery-Id'](单数 header)。 - undefined
@maxigs 谢谢。我已经更新了答案以反映这一点。 - undefined
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接