如何在Rails启动时创建线程?

我正在尝试在Rails启动时创建一个线程,该线程将在应用程序的整个生命周期内运行。 奇怪的是,我已经使用了另一个我正在运行的线程。 我复制了那个(工作)代码并将其用作新线程新代码的样板。 但线程不会启动。

  • 代码在config / initializers中(这是正确的位置吗?)。
  • 文件以’z _…’开头命名,以确保它最后运行。
  • Rails 3.2.6

以下是代码的一般结构:

class Blah def self.the_thread The_Model.transaction do # do some database stuff # ... end TheThread = Thread.new do while true do the_thread sleep 5.seconds end end end 

打开一个rails控制台并检查Blah :: TheThread会显示一个似乎没有运行的死线程。 在类的声明中,或者在方法中似乎没有任何错误,因为我可以在打开rails控制台时运行该方法并且它工作得很好。 另外,如果我手动输入rails控制台上面产生线程的确切代码(TheThread = Thread new do …),它就可以正常工作(每隔5秒唤醒一次,做它的事情,再次睡觉)。

同样,奇怪的是,在这个完全相同的应用程序中,这个用于在Rails中生成一个简单线程的精确模板曾经为我工作过。

如果有人对我认为是一个奇怪的问题有一些可能的见解,我会全力以赴。

谢谢。

编辑:新信息 – 我只是注释掉了事务调用(和匹配结束),它工作正常。 我不知道交易可能会干扰什么。 我删除了我的其他自定义初始化程序脚本,目录中唯一的其他程序是默认的,或属于设计的。 我仔细阅读过,并没有看到任何交易。

更多新信息。 我在线程代码的末尾添加了’TheThread.abort_on_exception = true’。 当我启动rails时,我现在得到一个exception’ArgumentError:在一个封闭的数据库上调用prepare:rollback transaction(ActiveRecord :: StatementInvalid)’。 错误发生在sqlite3 gem中。 我有sqlite3 gem版本1.3.6和sqlite-ruby gem版本1.3.3。 我已经搜索了错误并发现几个post抱怨同样的错误,但没有看到任何解决方案。

我不再认为这是一个线程问题,而是一个数据库问题,但更改这篇文章的标题为时已晚。

这只是:我在线程代码的顶部放置了一个’sleep 15.seconds’(就在它进入while循环之前)并且清除了问题。 但我仍然想知道是什么导致了这个问题,以及什么是“非黑客”解决方案。 出于某种原因,此代码运行时数据库尚未就绪。 我的初始化代码是否只是在错误的地方?

我真的建议看另一种实现这个的方法。 除非你在生产时真的需要每个实例增加一个额外的线程(想象一下设置3-4个瘦/杂种/等服务器 – 每个都有额外的线程),有更好的方法去做。

选项1 – 最简单 – 只是创建一个执行任务的控制器操作,然后使用wget和cron定期触发该操作。

 20 * * * * /usr/bin/wget --quiet -O - 'http://www.mydomain.com/my_controller/my_action' 

这里的问题是你必须处理身份validation/访问控制 – 除非你真的不在乎一些随机用户是否可以触发你的工作(坦率地说,有时非常简单的工作就是这种情况)。

选项2 – 使用Clockwork / Sidekiq或BackgroundRb或在后台运行任务的其他方式。 我在一个生产应用程序中完成了这个,它运行得非常好。 我选择了Clockwork和Sidekiq,我的预定任务看起来像这样:

应用程序/工人/ daily_worker.rb:

 class DailyWorker include Sidekiq::Worker def perform # do stuff here end end 

clockwork.rb:

 require 'clockwork' require 'sidekiq' Dir["app/workers/*"].each {|f| load f } module Clockwork every 1.day, 'daily.jobs', :at => "00:30" do DailyWorker.perform_async end end 

这对我来说似乎是最好的解决方案 – 它只需要我大约15分钟才能完成并运行。