0

これは私には本当に奇妙です。何時間もイライラしています。RUN リクエストを受信すると、RUNNER は永久に実行されるバックグラウンド スレッドを開始します。いつでも、実行中のスレッドは 1 つだけです (私はミューテックスを使用しています)。問題は、ステータス リクエストの場合、 true を返す場合と false を返す場合があることです。

(バックエンド スレッドは永久に実行されるため、done メソッドが呼び出されることはありません。したがって、is_running? が false になる可能性はありません)

#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
4

1 に答える 1

4

簡単な答え: これはできません。

長い答えは、Rails は受信リクエストを処理する1 つ以上のプロセスで構成されているということです。これらのプロセスのいずれかでランダムにスレッドを開始しても、そのis_running?フラグがメソッドがトリガーさtrueれたプロセス以外のプロセスになることはありません。run

ほとんどの Rails ホスティング環境では、プロセスが頻繁に作成および破棄されますが、プロセスが現在処理しているリクエストよりも長く存続するという保証はありません。これは、スレッドが予期せず強制終了される可能性があることを意味します。

Rails は厳密には要求応答システムです。バックグラウンド プロセスが必要な場合は、Rack を介して関与するものではなく、スタンドアロン スクリプトとして作成する必要があります。

たとえば、Rails 環境内で実行される実行時間の長いスクリプトを作成することは可能ですrails runnerが、これらはアプリケーションとは別に開始する必要があります。通常は、systemctlまたはのようなプロセス スーパーバイザを使用して、godこれを開始し、実行し続けます。

ユースケースによっては、遅延ジョブのようなジョブ処理システムの方が適している場合があります。これは、Web 向けの Rails プロセス モデルに適合しない断続的な「バックグラウンド タスク」を実行するのに最適です。

于 2013-06-28T03:14:24.920 に答える