我正在尝试在Rails启动时创建一个线程,该线程将在应用程序的整个生命周期内运行。奇怪的是,我已经使用了另一个我正在运行的线程。我复制了(工作)代码并将其用作新线程的新代码的样板。但线程不会启动。
以下是代码的一般结构:
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时,我现在得到一个异常'ArgumentError:prepare on a closed database:rollback transaction(ActiveRecord :: StatementInvalid)'。错误发生在sqlite3 gem中。我有sqlite3 gem版本1.3.6和sqlite-ruby gem版本1.3.3。我已经搜索了错误并发现有几个帖子抱怨同样的错误,但没有看到任何解决方案。
我不再认为这是一个线程问题,而是一个数据库问题,但更改这篇文章的标题为时已晚。
这就是:我在线程代码的顶部放置了一个'sleep 15.seconds'(就在它进入while循环之前)并且清除了问题。但我仍然想知道是什么导致了这个问题,以及什么是“非黑客”解决方案。出于某种原因,此代码运行时数据库尚未就绪。我的初始化代码是否只是在错误的位置?
答案 0 :(得分:1)
我真的建议另外一种方法来实现它。除非你去生产时真的需要一个额外的线程每个实例(想象设置3-4个瘦/杂种/等服务器 - 每个都有额外的线程),有更好的方法去做它
选项1 - 最简单 - 只是创建一个执行任务的控制器操作,然后使用wget和cron定期触发该操作。
20 * * * * /usr/bin/wget --quiet -O - 'http://www.mydomain.com/my_controller/my_action'
这里的问题是你必须处理身份验证/访问控制 - 除非你真的不在乎某个随机用户是否可以触发你的工作(坦率地说,有时非常简单的工作就是这种情况)。
选项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分钟才能完成并运行。