How to create thread at Rails startup?

左心房为你撑大大i 提交于 2020-01-02 11:01:10

问题


I'm trying to create a thread at Rails startup which will run throughout the lifetime of the app. The strange thing is, I already had this working with another thread I was running. I copied that (working) code and used it as boilerplate for the new code for the new thread. But the thread won't fire up.

  • Code is in config/initializers (is this the correct place?).
  • File is named starting with 'z_...' to insure it runs last.
  • Rails 3.2.6

Here is the general structure of the code:

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

Opening a rails console and examining Blah::TheThread reveals a dead thread that appears not to ever have run. There don't seem to be any errors in the declaration of the class, nor in the method because I can run the method when I open a rails console and it works just fine. Also, if I manually type into the rails console the exact code above which spawns the thread (TheThread = Thread new do ...), it works just fine (wakes up every 5 seconds, does its thing, sleeps again).

Again, the weird thing is, this exact boilerplate for spawning a simple thread in Rails worked for me before, in this exact same application.

If anyone has some possible insights into what I consider to be a strange problem, I'm all ears.

Thanks.

EDIT: New information - I just commented out the transaction call (and matching end) and it works fine. I don't know what the transaction could be interfering with though. I removed my other custom initializer script, and the only other ones in the directory are either default ones, or one that belongs to devise. I perused them, and didn't see any transactions going on.

More new info. I added 'TheThread.abort_on_exception = true' at the end of the thread code. When I startup rails I now get an exception 'ArgumentError: prepare called on a closed database: rollback transaction (ActiveRecord::StatementInvalid)'. The error is happening in the sqlite3 gem. I have sqlite3 gem version 1.3.6 and sqlite-ruby gem version 1.3.3. I have googled the error and found several posts complaining about the same error, but have not seen any solutions.

I no longer consider this to be a thread problem, but rather a database problem, but too late to change the title of this post.

THIS JUST IN: I put a 'sleep 15.seconds' right at the top of the thread code (just before it goes into the while loop) and that clears the problem up. But I'd still like to know what is causing the problem, and what a 'non-hacked' solution would be. For some reason the database isn't ready when this code runs. Is my initialization code simply in the wrong place?


回答1:


I would really recommend looking at another way to implement this. Unless you really need 1 extra thread per instance when you go to production (imagine setting up 3-4 thin / mongrel / etc. servers - each will have the extra thread), there's better ways to go about it.

Option 1 - the simplest - is just to create a controller action that will execute your task, and then use wget and cron to trigger that action regularly.

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

The problem here is that you've got to deal with authentication / access control - unless you really don't care if some random user can trigger your job (which, frankly, is sometimes the case for very simple jobs).

Option 2 - use Clockwork/Sidekiq or BackgroundRb or some other way of running tasks in the background. I've done this in a production app, and it works very nicely. I chose Clockwork and Sidekiq, and my scheduled tasks look something like this:

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

This to me seemed like the best solution - and it only took me about 15 minutes to get it all up and running.



来源:https://stackoverflow.com/questions/14413361/how-to-create-thread-at-rails-startup

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!