这对我来说真的很奇怪。几个小时都感到沮丧。一旦收到RUN请求,RUNNER将启动一个永远运行的后台线程。在任何时候,只有一个正在运行的线程(我使用互斥锁)。 问题是,对于状态请求,有时它返回true,有时它返回false 。
(完成方法从未被调用,因为后端线程将永远运行,所以is_running没有办法?可能是假的)
#config/initializers/some_init.rb
RUNNER = Runner.instance
#app/controllers/some_controller.rb
class SomeController < ApplicationController
def run
RUNNER.run {
loop do
Rails.logger.debug "backend thread running #{Time.zone.now}"
sleep(5)
end
}
end
def status
Rails.logger.debug RUNNER.inspect
RUNNER.is_running?
end
end
#lib/runner.rb
require 'singleton'
class Runner
include Singleton
def initialize
@running = false
@mutex = Mutex.new
end
def run(&blk)
@mutex.synchronize do
return if @running #only one job run is allowed at anytime
@running = true
@thr = Thread.new(self) do |r|
blk.call
r.done
end
end
end
def is_running?
@mutex.synchronize{ @running }
end
private
def done
@mutex.synchronize {@running = false}
end
end
答案 0 :(得分:4)
简短回答:你不能这样做。
答案很长,Rails由一个或多个进程组成,它们为传入的请求提供服务。随机启动其中一个进程中的线程不会使is_running?
标志在除true
方法被触发的进程之外的任何进程中变为run
。
大多数Rails托管环境都会经常创建和销毁进程,但不保证您的进程的活动时间比其当前正在处理的请求长。这意味着你的线程很可能会被意外杀死。
Rails严格来说是一个请求 - 响应系统。如果您需要后台进程,则必须将其创建为独立脚本,而不是通过Rack创建的内容。
可以创建在Rails环境中运行的长时间运行的脚本,例如,以rails runner
开头,但这些必须独立于您的应用程序启动。通常情况下,您使用像systemctl
或god
这样的流程主管来启动它并使其保持运行。
根据您的使用案例,delayed job等作业处理系统可能更适合您。这非常适合执行间歇性&#34;后台任务&#34;这不适合面向网络的Rails流程模型。