web-dev-qa-db-ja.com

Ruby on Rails:物事をバックグラウンドで実行する方法は?

新しいリソースが作成され、リソースの準備が整う前にいくつかの長い処理を実行する必要がある場合、その処理をどのように送信しますかバックグラウンドに場所Webアプリケーションへの現在の要求または他のトラフィックを保持しません

私のモデルでは:

class User < ActiveRecord::Base
 after_save :background_check

 protected
 def background_check
  # check through a list of 10000000000001 mil different
  # databases that takes approx one hour :)
  if( check_for_record_in_www( self.username ) )
    # code that is run after the 1 hour process is finished.
    user.update_attribute( :has_record )
  end
 end
end
29
Stefan

以下のRailscastを必ずチェックしてください。

彼らはRailsで可能なあらゆる方法で(キューの有無にかかわらず...)バックグラウンドプロセスを実行する方法を説明します...)

39
ujh

別のプロセスを開始します。これはおそらくsystemを使用して最も簡単に実行できます。「Nohup」を前に付け、渡したコマンドの最後に「&」を追加します。 (コマンドが引数のリストではなく、1つの文字列引数であることを確認してください。)

スレッドを使用するのではなく、この方法で実行する理由はいくつかあります。

  1. I/Oを実行する場合、Rubyのスレッドは少し扱いに​​くい場合があります。プロセス全体がブロックされないように注意する必要があります。

  2. 別の名前でプログラムを実行すると、 'ps'で簡単に識別できるので、FastCGIバックエンドが乱暴になっていると誤って判断したり、強制終了したりすることはありません。

実際、開始するプロセスは「デーモン化」されている必要があります。ヘルプについては、 Daemonize クラスを参照してください。

7
Curt J. Sampson

Herokuホスティングプラットフォームで動作し、セットアップが途方もなく簡単だったため、私は「delayed_job」gemを実験しています。

GemにGemを追加します。bundle installRails g delayed_jobrake db:migrate次に、次のコマンドでキューハンドラを開始します。

Rails_ENV=production script/delayed_job start

あなたの長いプロセスであるメソッド呼び出しがある場所、つまり

company.send_mail_to_all_users

に変更します。

company.delay.send_mail_to_all_users

Githubの完全なドキュメントを確認してください: https://github.com/collectiveidea/delayed_job

6
Sujimichi

自分で作成するのではなく、既存のバックグラウンドジョブサーバーを使用するのが理想的です。これらは通常、ジョブを送信して一意のキーを与えることができます。その後、キーを使用して、webappをブロックせずに定期的にjobserverにジョブのステータスを照会できます。 これは素晴らしいまとめです さまざまなオプションがあります。

2
Martin DeMello

spawn は、プロセスをforkし、バックグラウンドで処理を実行し、この処理が開始されたことを確認するための優れた方法だと思います。

1
Vojto

私はbackgroundrbを使用するのが好きです。Niceを使用すると、長いプロセス中にそれと通信できます。 Railsアプリでステータスを更新できます

1

何について:

def background_check
   exec("script/runner check_for_record_in_www.rb #{self.username}") if fork == nil
end

プログラム "check_for_record_in_www.rb "は別のプロセスで実行され、ActiveRecordにアクセスして、データベースにアクセスできるようになります。

0
Edu