2

Rails にアプリケーションがあり、ユーザーがある特定のページから別のページに移動するときに、データベース ストアド プロシージャを非同期的に実行しようとしています。ユーザーは、ストアド プロシージャの実行中にナビゲーションを続行する必要があります。

手順が終了したときにコールバックを行う必要はありません。バックグラウンドで実行するだけで済みます。

次のコードを使用しようとしています。

require 'eventmachine'
require 'em-http'
require 'fiber'

def async_fetch(url)
  f = Fiber.current
  http = EventMachine::HttpRequest.new(url).get :timeout => 10
  http.callback { f.resume(http) }
  http.errback { f.resume(http) }

  return Fiber.yield
end

EventMachine.run do
  Fiber.new{
    url = url_for :controller => 'common', :action => 'execute_stored_procedure'
    data = async_fetch(url)
    EventMachine.stop
  }.resume
end

ここでの問題は、ストアド プロシージャの開始時にユーザーを別のページにリダイレクトする必要がありますが、次のページは「保留中」のままで、プロシージャが終了したときにのみレンダリングされることです。

--threaded オプションを使用してサーバーとして (開発環境で) thinを使用しようとしましたが、成功しませんでした。現在、運用サーバーで Phusion Passenger Enterprise をマルチスレッド モードで使用することを考えていますが、これは商用バージョンであり、実行されます。トライアルはありません。私が必要としているものではないのではないかと心配しています。

これを達成するための良い解決策を知っている人はいますか? ストアド プロシージャを実行するには、アプリケーションが実行されているのと同じ Web サーバーにリクエストを送信する必要があるため、Web サーバーは一度に複数の接続 (マルチスレッド) を受け入れる必要がありますが、正しいですか?

役立つ情報:

  • ルビー 1.9.3p385
  • レール 3.2.13
  • SQL Server 2012

発達:

  • Linux lucid32 2.6.32-45-generic #102-Ubuntu (vagrant マシン)
  • シンウェブサーバー

製造:

  • Linux デビアン 2.6.32-5-xen-amd64
  • Apache / Phusion パッセンジャー

どんな助けでも本当に感謝しています。

更新 #1

ジェシーさんのお勧めでセルロイドにしてみました。これが私のコードです:

require 'celluloid/autostart'
class PropertyWorker
  include Celluloid

  def engage(args)
    ActiveRecord::Base.execute_procedure("gaiainc.sp_ins_property_profiles", args[:id])
  end
end

...

def create
    @property = Property.new(params[:property])

    respond_to do |format|
      if @property.save
        PropertyWorker.new.async.engage({:id => @property.id})
        format.html { redirect_to new_enterprise_property_activation_url(@property.enterprise.id, @property.id) }
        format.json { render json: @property, status: :created, location: @property }
      else
        format.html { render action: "new" }
        format.json { render json: @property.errors, status: :unprocessable_entity }
      end
    end
end

その後、アクション「作成」が呼び出されると、レコードが作成され、ストアド プロシージャが開始されますが、次のページはレンダリングされず、プロシージャが終了するまでリクエストはブラウザで「保留中」のままになります。手順が完了するとすぐに、ページがレンダリングされます。

何が起こっているのかわかりません。手順はバックグラウンドで実行されるはずではありませんでしたか?

4

2 に答える 2

3

このような場合は、SidekiqまたはCelluloidのいずれかをお勧めします。あなたがしたいことは、スレッドをスピンオフして何かを実行し、呼び出しプロセスへのアクセスを返し、それを継続させることです。

Sidekiq を実行するには別のプロセス (および Redis) が必要ですが、Celluloid では必要ありません。そうでなければ、それらは似ています。

サイドキク:

class AsyncProc
  include Sidekiq::Worker

  def perform(args)
    CodeToExecuteStoredProcedure.engage! args
  end
end

次のように呼び出します。

AsyncProc.perform_async {whatever: arguments, you: want}

これにより、Redis でジョブがスケジュールされ、予備の Sidekiq ワーカーに時間があるときに実行されます。

セルロイド:

require 'celluloid/autostart'
class AsyncProc
  include Celluloid

  def engage(args)
    CodeToExecuteStoredProcedure.engage! args
  end
end

そしてそれを呼び出すには:

AsyncProc.new.async.engage {whatever: arguments, you: want}

これは、ほとんどすぐに非同期で実行されます。

于 2013-05-22T14:36:11.840 に答える
1

リクエスト/レスポンス スレッドから非同期で何かを実行したい場合は、そのように聞こえますが、これを行うにはバックグラウンド処理システムを使用する必要があります。

これを行うさまざまな gem があります。より一般的なオプションの一部として、 DelayedJobResque、およびSidekiqを調べてください。通常、実行する必要がある、または現在実行中のタスクを追跡するために、バッキング ストア (Redis、MongoDB、Rails データベース) が必要になります。

あるいは、GVL をロックしない個別のプロセスを実際に生成するため、Unicorn が機能する可能性があります。

于 2013-05-22T14:26:50.330 に答える