2

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

  • 代码在 config/initializers 中(这是正确的地方吗?)。
  • 文件以“z_...”开头命名,以确保它最后运行。
  • 导轨 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 中生成简单线程的确切样板文件在这个完全相同的应用程序中对我有用。

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

谢谢。

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

更多新信息。我在线程代码的末尾添加了“TheThread.abort_on_exception = true”。当我启动 rails 时,我现在得到一个异常“ArgumentError:在关闭的数据库上调用准备:回滚事务(ActiveRecord::StatementInvalid)”。错误发生在 sqlite3 gem 中。我有 sqlite3 gem 版本 1.3.6 和 sqlite-ruby gem 版本 1.3.3。我用谷歌搜索了这个错误,发现几个帖子抱怨同样的错误,但没有看到任何解决方案。

我不再认为这是一个线程问题,而是一个数据库问题,但是来不及改变这篇文章的标题。

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

4

1 回答 1

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

发条.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 分钟就将它全部启动并运行起来。

于 2013-01-22T18:14:44.383 回答