2013-01-24 10 views
5

私は、基本的にユーザがボットとチャットすることを可能にするサービスを構築しており、ボットはユーザが送信したチャットでいくつかの奇妙な処理を行い、最終的に意味のあるデータで返信します。基本的にAardvarkがどのように(?Rails + XMPP bot in background

私はボットを働いていて、今聞いていますが、私は別の重い持ち上げをする別のレールアプリを持っています。これらの部分はどちらも個別にうまく動作していますが、今では2つのインターフェイスについています。私の考えは、ボトル(基本的には小さなルビースクリプト)をResque経由でレールアプリにインターフェイスすることです。何か入って来るものは待ち行列に入り、取り上げられ、結果は再度待ち行列にプッシュされ、次にスクリプトは結果を返信します。

私はこのインタフェースを確立する方法に関して非常に明確ではありませんよ。

  1. は、私は熊手せずにそれを実行した場合、ボット
  2. をリロード/停止/起動するrakeタスクを記述する必要があります( Monitによって監視されている独立したプロセスと思われる)では、Resqueとのインタフェースやレールモデルへのアクセス方法を教えてください。

これらは非常に些細な質問かもしれませんが、私はうまく動作するかどうかを理解するのが苦労しています。

+0

ボットの開始/停止別の関心事です。そのためにはMonitがその選択肢の1つであり、監督のようなツール(https://github.com/ddollar/foreman)もそうです。私の本当の質問は、あなたのルビーアプリを非同期的または同期的に動かす必要があるかどうかです。同期インターフェースを手放すことができれば、あなたのボットは、単にレールアプリへのHTTPコールを行うことができ、人生は簡単です。 :) –

答えて

4

あなたのRailsアプリと、このボットデーモンとの間で通信するための3つの方法があります。(Railsのアプリからデータを引っ張ってプッシュ/)HTTPリクエストとしてのRailsアプリを呼び出すことにより

  1. はと直接対話することでデータベース

あなたはエンキューとResqを引いているのRedisデータベースに裏打ちされたResque作業キューシステムと相互作用することにより、Railsのアプリが使用する(可能性が高いのMySQL/Postgresの)

  • 、ジョブをさまざまなジョブキューから削除すると、APIを介して共有されているRedisデータベースに読み書きしているだけです。ボットとRailsの両方のアプリケーションは、ネットワークを介してRedis DBと通信します。

    私は、モットが管理するルビープロセスまたはレーキタスクとしてボットを直接実行することをお勧めします。あなたはすでにこれを行う方法を知っているように聞こえる。

  • 2

    ここでの主な問題は、「ただ」キューであるResqueを曲げようとするのではなく、メッセージング(IMではなくIPCのような)のための別の解決策が必要だと思います。オプションの一部はamqp gem(AMQPプロトコル)またはzmq gem(ZeroMQプロトコル)ですが、Ruby標準ライブラリSocketクラス(good examples)を介して単純な古いUNIXソケットを使用することもできます。彼らはすべて賛否両論が異なるので、おそらくあなた次第です。

    1. ボット開始:

      その後、相互作用は、このようなもののように見えるかもしれません。

    2. BotがIPCメッセージの受信を開始します。
    3. Botは(XMPP経由で)送信者からのクエリを受信します。
    4. ボットはResqueを介してジョブをキューに入れます。
    5. ジョブはHTTP経由でRailsアプリケーションを呼び出します。
    6. Railsアプリは仕事の分担をしています。
    7. 誰か他の人が、クエリの内容を解決し、Railsアプリケーションを介して結果を入力します。
    8. Railsアプリケーションは、IPCメソッドを使用して結果をボットに送信します。
    9. Botは、(XMPP経由で)元の送信者に結果を送信します。

    いつものようにいくつかの変更があります。たとえば、あなたはResqueを一切必要としないと思います。ボットはリクエストをただちにRailsアプリケーションに渡すことができますが、負荷、達成したい応答時間、現在のアーキテクチャなどによって異なります。Resqueジョブは、Railsアプリケーションが結果を返してからジョブを待つことがあります(Railsアプリではなく)IPCを使用します。他のバリエーションがありますが...

    は、私は、そうしないボットに

    をリロード/停止/起動するrakeタスクを記述する必要があります。いつ、どのように実行するかは、あなた次第です。結局のところ、Rakeは、複数のRubyスクリプトをまとめてそれらの間の依存関係を作成する便利な方法と同じように見ることができます。ボットの周りに他のタスクがあると思うなら(クリーンアップ、配備など)、利便性のためにRakeを使うのは良いことです。まだリファクタリングしていない場合は、リファクタのボットのロジックをクラス化し、それを初期化するためにRakeタスクを使用します。しかし、それを残してそのままスクリプトを実行すると(monit、独自のinit.dスクリプト、アドホックなどを使って)うまくいくでしょう。

    rakeを使わずに(Monitが監視している独立したプロセスと思われる)、それを実行すると、Resqueとのインタフェースやレールモデルへのアクセス方法は?

    レーキはこれに影響しません。 OSの観点から見ると、Rakeとあなたのボットを介してRake経由で、あるいはスタンドアロンのスクリプトとしてResqueを実行しても、それは問題ではありません。また、ResqueはRedisがどこかで動作する必要があることに注意してください。

    は、私は、これらは非常に些細な質問

    ませんまったく

    かもしれません知っています。私はそれが些細なものと見なすことができるようになるまでには時間がかかると思う。

    0

    コードをイニシャライザで実行し、すべてのRailsモデルやライブラリにフルアクセスできます。

    この方法では、あなたのロボットがあなたのRailsアプリケーションの中にあるので、あなたとあなたのRailsアプリケーションとの間で "通信"する必要はありません。

    定型コードは次のようであろう:

    設定/イニシャライザ/ background_app_tasks.rb

    class BackgroundWorker 
    
         #------------------------------- 
         def initialize(operation='normal') 
         @exit = false 
         @lock = Mutex.new # For thread safety 
         @thread = nil 
         say "Starting in '#{operation}' mode..." 
         case operation 
          when 'normal' 
          @thread = Thread.new() { loopme  } 
          when 'cleanup' 
          @thread = Thread.new() { cleanup  } 
          when 'nothing' 
          #startup without threads 
         end 
         @thread.run if @thread 
         end 
    
         #------------------------------- 
         def exit! 
         begin 
          return if @exit # #stop? 
          say "Exiting #{}, waiting for mutex..." 
          @lock.synchronize { 
           say "exiting thread #{@thread.to_s || '<sem nome>' }..." 
           @exit = true # #stop 
          } 
         rescue Exception => e 
          exceptme(e) 
         end 
         end 
    
         #------------------------------- 
         def loopme 
    
         at_exit { exit! } 
         i=0; ok=false; 
    
         nap = 30 
    
         while true do 
          begin 
           break if @exit 
           i+=1 
    
           #lock mutex for processing... 
           @lock.synchronize { 
    
            #.... do some work .... 
    
           } 
          rescue StandardError => e 
    
           #.... 
    
          end 
    
          sleep(nap) 
         end 
         end 
    
    end #class 
    
    # ------ M A I N -------- 
    
    Thread.abort_on_exception=false 
    e = BackgroundWorker.new(OPERATION)