Rails 4:如何在单独的线程中发送邮件?

时间:2015-04-28 03:48:05

标签: ruby-on-rails multithreading email ruby-on-rails-4

我有一个应用程序,当管理员做某事时,需要偶尔向整个用户群发送电子邮件。这工作正常,但是当有很多用户时,管理员的页面将等到所有邮件都被发送,这是不可取的。

为了缓解这个问题,我尝试在一个新主题中发送电子邮件:

t = Thread.new do
  User.all.each do |user|
    Mailer.email(user).deliver
  end
end
at_exit{ t.join }

这很好,但是在我的测试套件中,我无法测试以确保电子邮件发送有效:

# This test now fails with the new Thread above
test "admin action should send email blast" do
  assert_difference("ActionMailer::Base.deliveries.count", User.count) do
    post :action
  end
end

所以我的问题是:

  1. 这种方法是在新线程中发送电子邮件的最佳方式吗?或者是否有可用于处理此类交互的宝石?
  2. 如果在新线程中完成发送,如何测试我的测试套件中是否发送了电子邮件?有没有办法检查等待所有线程完成?

4 个答案:

答案 0 :(得分:2)

在rails 4.2中有一个特殊的类来处理名为ActiveJob的作业,活动作业允许你为另一个进程排队长任务以在后台处理它们,你也可以将任务排队一段时间,比如例如“明天早上8点发送此邮件”。

要处理这些队列,你需要选择一个后端来处理它们,这里是list of backends that support ActiveJob

每个都有它的优点和缺点,例如sidekiq是一个多线程处理程序,因此它使用较低的内存,而例如sucker punch使用与主服务器相同的线程,因此它使用的内存少得多,如果你有低内存服务器,无法处理第二个ruby线程。

至于测试部分,rails guide已经解释了如何测试您的电子邮件和测试电子邮件是否排队等测试,并测试是否呈现了正确的模板,以及它是否包含正确的文本。

答案 1 :(得分:2)

我认为你想要异步发送邮件,为此你可以使用许多宝石 - 例如 - 延迟工作,sidekiq等。我个人建议使用sidekiq作为它更快,并在场景后面的内存数据库中使用Redis。

使用Rails 4.2,引入了活动作业,因此使用它有利于您可以随时从一个排队系统切换到另一个排队系统而无需担心,您可以指定想要的排队机制

module YourApp
 class Application < Rails::Application
  # Be sure to have the adapter's gem in your Gemfile
  # and follow the adapter's specific installation
  # and deployment instructions.
  config.active_job.queue_adapter = :sidekiq
 end
end

答案 2 :(得分:1)

我更喜欢使用基于队列的方法来执行异步任务。 [延迟工作](https://github.com/collectiveidea/delayed_job)是一种选择,但我更喜欢使用[sidekiq](http://sidekiq.org)。

[Here](http://blog.remarkablelabs.com/2013/01/using-sidekiq-to-send-emails-asynchronously)是使用sidekiq异步发送电子邮件的示例。

答案 3 :(得分:0)

在单独的线程中发送电子邮件的最佳方式是使用延迟的作业或类似的gem。

https://github.com/collectiveidea/delayed_job

使用延迟作业gem,您还可以在预定时间发送电子邮件或在不同的线程中执行其他操作。

另一种选择是使用sidekiq,安装sidekiq gem并将此行添加到application.rb文件

config.active_job.queue_adapter = :sidekiq