【问题标题】:Sending Email with Delayed_Job使用 Delayed_Job 发送电子邮件
【发布时间】:2017-02-22 22:46:47
【问题描述】:

我有一个我认为可以通过Delayed_Job 发送电子邮件的工作设置。但是,我还没有收到我的测试电子邮件,并且延迟几天等待更多的事情发生是不切实际的。我需要弄清楚:

  1. 是什么问题导致电子邮件无法发送。
  2. 如何在不等待几天的情况下进行测试。

我是Delayed_Job的新手,请原谅新手的错误。

这是包含send_reminder_emails 方法的模型。没有.delay(run_at: self.mail_date) 位,它们功能齐全,所以至少我知道很多工作:

class Reminder < ActiveRecord::Base
  belongs_to :user
  before_save :create_mail_date
  after_save :send_reminder_emails
  extend FriendlyId
  friendly_id :name, use: [:slugged, :finders]

  def create_mail_date
    @schedule = IceCube::Schedule.new(self.date)
    case self.repeating
    when "Weekly"
        @schedule.add_recurrence_rule(
            IceCube::Rule.weekly
        )
    when "Monthly"
        @schedule.add_recurrence_rule(
            IceCube::Rule.monthly.day_of_month(self.date.mon)
        )
    when "Yearly"
        @schedule.add_recurrence_rule(
            IceCube::Rule.yearly.day_of_year(self.date.yday)
        )
    end
    if self.repeating
        self.date = @schedule.next_occurrence(Time.now)
    end
    self.mail_date = self.date - 7.days
  end

  private

  def send_reminder_emails
      if self.reminder
         ReminderMailer.delay(run_at: self.mail_date).reminder_send(self.user, self).deliver_now
         self.create_mail_date
     end
  end
  handle_asynchronously :send_reminder_emails

end

schedule 的引用是通过Ice_Cube gem 引用的,并且所有日期内容都已通过我的控制台进行了测试并且正在运行。这是我的reminder_mailer.rb

class ReminderMailer < ApplicationMailer
  default from: "man@manlyartofbbq.com"

  def reminder_send(user, reminder)
    @user = user
    @reminder = reminder

    mail(to: user.email, subject: "Reminder! #{reminder.name} is fast approaching!")
  end
end

我从他们的 Rails 4 自述文件中逐步安装了Delayed_Job。感谢任何帮助解决此邮件的延迟部分!

【问题讨论】:

  • 在 Rails 控制台中运行 Delayed::Job.all 会得到什么。
  • @Dinesh,我收到了NameError: uninitialized constant Delayed from (pry):12:in __pry__'` 我觉得这是一个不好的信号。
  • 这个有 git repo 吗?
  • 一种可能性:上次我查看 DelayedJob 时,它旨在检测邮件程序参数何时是 ActiveRecord 实例,在这种情况下,保存在作业队列中的不是对象而是对象的 id 字段.当作业准备好运行时,它使用 id 进行查找。我想这是一个优化。但是,如果您使用未保存的 ActiveRecord 作为参数,则查找失败,任务发出日志记录并终止。在这里,例如如果 IceCube::Schedule 是 ActiveRecord 的子类,那很可能就是正在发生的事情。
  • 嗨。您能否从“ ReminderMailer.delay(run_at: self.mail_date).reminder_send(self.user, self).deliver_now”中删除“deliver_now”并检查

标签: ruby-on-rails actionmailer delayed-job


【解决方案1】:

您可以通过在特定时间安排作业来使用活动作业发送邮件。

Active Job 是一个用于声明作业并使它们在各种排队后端运行的框架。这些工作可以是从定期安排的清理、计费到邮寄的所有工作。任何可以分割成小的工作单元并并行运行的东西,真的。

为了在生产环境中排队和执行作业,您需要设置一个排队后端,也就是说,您需要决定 Rails 应该使用的第 3 方排队库。 Rails 本身只提供了一个进程内排队系统,它只将作业保存在 RAM 中。如果进程崩溃或机器被重置,那么所有未完成的作业都将丢失,并使用默认的异步后端。这对于较小的应用程序或非关键作业可能没问题,但大多数生产应用程序都需要选择一个持久的后端。

Active Job 具有用于多个队列后端(Sidekiq、Resque、Delayed Job 等)的内置适配器。要获取适配器的最新列表,请参阅ActiveJob::QueueAdapters. 的 API 文档

配置队列适配器后,创建发送邮件的作业

class RemainderMailerJob < ApplicationJob
  queue_as :default

  def perform(user, remainder)
   ReminderMailer.reminder_send(user, reminder).deliver
  end
end

要在特定时间发送邮件,您需要将作业排入队列并使其在特定时间执行。如果您需要在 7 天后发送邮件,请在需要时调用这段代码。

RemainderMailerJob.set(wait: 1.week).perform_later(user, remainder)

现在这个 Job 将在 1 周后执行,然后在那个时候调用 mailer,所以你的邮件将在特定的日期发送。

如果您知道具体的日期时间,那么您可以使用

RemainderMailerJob.set(wait_untill: <Specific date>).perform_later(user, remainder)

如果您对当前工作有任何疑问,请联系Active Job Basics

【讨论】:

  • 感谢您非常彻底的回复。问题是我试图让它在数据库确定的日期发送,而不是在作业排队时发送。我不能使用“等待:1.week”之类的东西,因为它可能是一周、一个月或一天。这有意义吗?
  • @Liz 你可以使用GuestsCleanupJob.set(wait_until: &lt;A specific date&gt;).perform_later(guest)
  • @Liz 我已经对答案进行了更改,看看它。
  • 即使有这个添加(太棒了),我仍然得到一个run_at: Fri, 21 Oct 2016 23:37:08 UTC +00:00,(它显示延迟工作中的run_at日期作为节省的时间,而不是我打电话时指定的mail_date RemainderMailerJob.set(wait_until: self.mail_date).perform_later(user, remainder) 在我的方法中。
  • @Liz 我已经使用RemainderMailerJob.set(wait_until: 3.days.from_now).perform_later(user, remainder) 使用示例作业对其进行了测试,我得到的结果是#&lt;RemainderMailerJob:0x007fe37c165c08 @arguments=[157, 0], @job_id="6543fe81-4ef5-4228-b875-4508dfd9b77e", @queue_name="default", @priority=nil, @provider_job_id="90a61e2d98520dfec0473cd3", @scheduled_at=1477552788.4407418&gt; 其中scheduled_at 包含作业计划运行的时间。如果可能的话,您可以在控制台中尝试此过程并将结果作为评论发布
【解决方案2】:

当您使用延迟作业发送邮件时,初始化邮件程序的延迟作业时无需添加'deliver'或'deliver_now'。所以

ReminderMailer.delay(run_at: self.mail_date).reminder_send(self.user, self)

自己会工作。

将您的“self.mail_date”转换为还包括您要发送邮件的时间。只传递日期是行不通的。基本上 run_at 应该指定日期和时间。

请查看“Rails 3 Mailers”标题下的“delayed_job”github 链接 https://github.com/collectiveidea/delayed_job

【讨论】:

  • 感谢您发现这一疏忽。当我执行Delayed::Job.all 时,这些项目现在会出现在我的控制台中。但是,run_at 仍然是项目进入队列的任何时间,而不是数据库中的 mail_date。想法?
  • run_at 参数用于传入“时间”而不是“日期”。延迟的工作永远不能安排在某个日期,而只能安排在时间上。我猜,您只能为日期为作业运行当前日期的记录运行延迟作业。并在“run_at”参数中传递执行时间。希望这可以帮助。对我的回答投赞成票将不胜感激。 :)
  • 根据this之类的问题看来应该是可以的...
  • 我向朋友道歉。这是正确的。我只是想确定“self.mail_date”是否是日期类型?还是日期时间类型?传递一个带时间的日期应该有效。我猜你可以试一试。
  • 酷。请尝试,如果可行,也请接受我的回答。 :) 我也在答案中添加了新的变化。提前致谢。
【解决方案3】:

我已经看到当属性保护配置错误时会发生这种情况。 (通常在升级 Rails 版本时留下一些杂物的遗留应用程序上。)

查看您是否可以从控制台设置字段:Delayed::Job.new(run_at: 1.year.from_now)。如果没有,那就是罪魁祸首,您需要在您的应用中找出原因。

如果有效,那么我们仍然需要验证这是应用程序问题还是 DJ 错误。制作一个新的最小 Rails 应用程序,只使用一个延迟作业表并尝试重现它。如果你不能,那么你的应用程序中还有一些奇怪的东西。

【讨论】:

    猜你喜欢
    • 2012-01-25
    • 1970-01-01
    • 1970-01-01
    • 2016-04-17
    • 2017-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多