ruby-on-rails - 如何在Rails启动时创建线程?

标签 ruby-on-rails multithreading configuration initialization

我正在尝试在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中生成简单线程的精确样板在以前与我完全相同的应用程序中曾为我工作过。

    如果有人对我认为是一个奇怪的问题有一些可能的见解,那么我无所不能。

    谢谢。

    编辑:新信息-我只是注释掉事务调用(和匹配结束),并且工作正常。我不知道该交易可能会干扰什么。我删除了其他自定义初始化脚本,该目录中仅有的其他脚本是默认脚本或属于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”放在了上面,这解决了问题。但是我仍然想知道是什么导致了问题,以及什么是“非骇客”的解决方案。由于某些原因,运行此代码时数据库尚未准备就绪。我的初始化代码只是放在错误的地方吗?

    最佳答案

    我真的建议您寻找另一种方法来实现这一目标。除非在投入生产时每个实例真的需要1个额外的线程(想象设置3-4台瘦/杂种服务器等-每个服务器都会有额外的线程),否则会有更好的方法进行处理。

    选项1(最简单)只是创建一个 Controller Action 来执行您的任务,然后使用wget和cron定期触发该 Action 。

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

    这里的问题是,您必须处理身份验证/访问控制-除非您真的不在乎某个随机用户是否可以触发您的工作(坦率地说,对于非常简单的工作而言,有时是这样)。

    选项2-使用Clockwork/Sidekiq或BackgroundRb或其他在后台运行任务的方式。我已经在生产应用程序中做到了这一点,并且效果非常好。我选择了Clockwork和Sidekiq,我的预定任务如下所示:

    app/workers/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分钟即可将其全部安装并运行。

    关于ruby-on-rails - 如何在Rails启动时创建线程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14413361/

    相关文章:

    css - 在 Rails 中格式化 CSS 输出

    ruby-on-rails - rails : Controller-specific menu in layout

    c# - 让 MySqlConnection 空闲会导致超时吗?

    multithreading - 什么是clang中g++的-pthread equiv?

    c# - 如何在连接字符串中包含&符号?

    mysql - 如何查找特定时间之后的所有数据库行

    java - 在java线程中每隔一小时运行一次作业

    Spring JavaConfig,bean 的自定义作用域和注解

    ruby-on-rails - rails : Have initializer load before application. rb

    jquery - 打开 Bootstrap Modal 以在 Ruby on Rails 中编辑记录