5

基本的にユーザーがボットとチャットできるようにするサービスを構築しています。ボットは、ユーザーが送信したチャットで奇妙な処理を行い、最終的に意味のあるデータで返信します。基本的に、Aardvark が (?) を使用して機能する方法に似ています。

私はボットを機能させ、今聞いています。他のすべての面倒な作業を行う別のレールアプリがあります。これらの部分はどちらも個別にうまく機能しており、今は 2 つのインターフェイスを接続するのに行き詰まっています。私の考えは、Resque を介してボット (基本的には小さな Ruby スクリプト) を Rails アプリと接続することです。スクリプトは結果を返します。

このインターフェイスを確立する方法についてはあまり明確ではありません。

  1. ボットを開始/停止/リロードするには、rake タスクを作成する必要がありますか?
  2. rake なしで実行した場合 (おそらく Monit によって監視される独立したプロセスとして)、Resque とやり取りしたり、Rails モデルにアクセスしたりするにはどうすればよいですか?

これらは非常に些細な質問かもしれませんが、どちらがうまく機能し、セットアップをどのように進めるかを理解するのに苦労しています.

4

3 に答える 3

4

Railsアプリとこのボットデーモンの間で通信する方法は3つあります。

  1. RailsアプリをHTTPリクエストとして呼び出す(Railsアプリからのデータのプッシュ/プル)
  2. Railsアプリが使用するデータベース(Mysql / Postgresなど)と直接対話することによって
  3. Redisデータベースに支えられたResqueワークキューシステムと対話することによって

さまざまなジョブキューからResqueジョブをエンキューおよびプルする場合、APIを介して共有Redisデータベースに対して読み取り/書き込みを行うだけです。ボットとRailsアプリの両方が、ネットワークを介してRedisDBと通信します。

ボットを、monitが管理するrubyプロセスまたはrakeタスクとして直接実行することをお勧めします。あなたはすでにこれを行う方法を知っているようです。

于 2013-01-28T16:46:09.507 に答える
2

ここでの主な問題は、「単なる」キューである Resque を曲げようとするのではなく、メッセージング (IM ではなく IPC のようなもの) のための別のソリューションが必要であることだと思います。一部のオプションにはamqp gem (AMQP プロトコル) またはzmq gem (ZeroMQ プロトコル) がありますが、Ruby 標準ライブラリ Socket クラス (良い例) を介してプレーンな古い UNIX ソケットを使用することもできます。それぞれに長所と短所がありますので、あなたとあなたのニーズ次第です。

相互作用は次のようになります。

  1. ボットが起動します。
  2. ボットが IPC メッセージのリッスンを開始します。
  3. ボットは送信者から (XMPP 経由で) クエリを受信します。
  4. ボットは Resque を介してジョブをキューに入れます。
  5. ジョブは HTTP 経由で Rails アプリを呼び出します。
  6. Rails アプリは、その役割分担を行います。
  7. 誰かまたは何かがクエリを解決し、Rails アプリを介して結果を入力します。
  8. Rails アプリは、何らかの IPC メソッドを使用して結果をボットに送信します。
  9. ボットは結果を元の送信者に送信します (XMPP 経由)。

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

ボットを開始/停止/リロードするには、rake タスクを作成する必要がありますか?

いいえ、あなたはしません。いつ、どのように実行するかはあなた次第です。結局のところ、Rake は、複数の Ruby スクリプトをまとめてそれらの間に依存関係を作成するための便利な方法と見なすことができます。ボットを実行するだけでなく、他のタスク (クリーンアップ、デプロイなど) があると思われる場合は、利便性のために Rake を使用することをお勧めします。まだ行っていない場合は、ボットのロジックをクラスにリファクタリングし、Rake タスクを使用して初期化します。ただし、そのままにして、スクリプトをそのまま実行しても問題ありません (monit、カスタム init.d スクリプト、アドホックなどを使用)。

rake なしで実行した場合 (おそらく Monit によって監視される独立したプロセスとして)、Resque とやり取りしたり、Rails モデルにアクセスしたりするにはどうすればよいですか?

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

私はこれらが非常に些細な質問かもしれないことを知っています

いいえ、まったく。のような問題が些細なことと見なされるまでには、しばらく時間がかかると思います。

于 2013-02-03T04:36:41.913 に答える
0

コードをイニシャライザで実行するように配置し、すべての Rails モデルまたはライブラリに完全にアクセスできます。

この方法では、ボットは Rails アプリ内にあるため、ボットと Rails アプリの間で「通信」する必要はありません。

定型コードは次のようになります。

config/initializers/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)
于 2015-12-17T11:02:54.467 に答える