2013-01-24 23 views
5

我正在構建基本上允許用戶與機器人聊天的服務,然後機器人通過用戶發送的聊天進行一些奇怪的處理,並最終回覆一些有意義的數據。基本上類似於Aardvark使用(?)工作的東西。Rails + XMPP機器人背景

我的機器人工作,現在正在傾聽,我有一個單獨的導軌應用程序,將做所有其他繁重的工作。這兩個部分都單獨工作,現在我被困在接口兩個。我的想法是通過Resque與bot應用程序(基本上是一個小型的ruby腳本)進行接口 - 任何進入隊列的東西都會被接收,然後結果再次推回到隊列中,然後腳本會回覆結果。

我不爲如何建立這個界面非常清晰:

  1. 我是否需要寫一個rake任務啓動/停止/重載機器人
  2. 如果我不耙運行(據說Monit是一個獨立的進程),那麼我如何與Resque交互或訪問我的rails模型?

我知道這些可能是非常微不足道的問題,但我很難理解哪個更好,以及如何讓安裝程序進行。

+0

起始/機器人的止擋是一個單獨的問題。 Monit是一個選擇,就像工頭(https://github.com/ddollar/foreman)一樣。對我來說真正的問題是,你是否需要bot與你的ruby應用異步或同步工作。如果你可以脫離同步界面,你的機器人只需要對Rails應用程序進行HTTP調用,而且生活很簡單。 :) –

回答

4

有三種方式你的Rails應用程序,這個機器人守護進程間通信:

  1. 通過調用Rails應用程序作爲HTTP請求(推/拉從Rails應用程序數據)
  2. 通過直接與互動數據庫中的Rails應用程序使用(可能的Mysql/Postgres的)
  3. 通過與Resque工作隊列系統進行交互,通過Redis的數據庫

當你排隊,拉RESQ支持在各種Job隊列中工作時,您只需通過API讀取/寫入共享的Redis數據庫。 bot和Rails應用程序都通過網絡與Redis DB交談。

我建議直接運行bot作爲由monit管理的ruby進程或rake任務。這聽起來像你已經知道如何做到這一點。

2

我認爲這裏的主要問題是,您需要另一個消息傳遞解決方案(類似IPC的,而不是IM),而不是試圖彎曲Resque,它只是一個隊列。一些選項是amqp gem(AMQP協議)或zmq gem(ZeroMQ協議),但您也可以通過Ruby標準庫Socket類(good examples)使用普通的舊套接字套接字。他們都有不同的優點和缺點,所以它可能取決於你。

然後,交互可能看起來像這樣的事情:

  1. 博特開始。
  2. Bot開始偵聽IPC消息。
  3. Bot收到發件人的查詢(通過XMPP)。
  4. Bot通過Resque排隊工作。
  5. Job通過HTTP調用Rails應用程序。
  6. Rails應用程序完成其工作。
  7. 某人或某事可以解決任何查詢,並通過Rails應用程序輸入結果。
  8. Rails應用程序使用一些IPC方法將結果發送到機器人。
  9. Bot將結果發送給原始發件人(通過XMPP)。

像往常一樣可能會有一些變化。例如,我認爲你根本不需要Resque。殭屍程序可以簡單地將請求傳遞給Rails應用程序,但它取決於負載,您想要實現的響應時間,您當前的架構等。也許Resque作業可以等待Rails應用程序返回結果,然後返回作業(不是Rails應用程序)會使用IPC。還有其他一些變化......

我是否需要寫一個rake任務啓動/停止/重載機器人

不,你不知道。這取決於你如何以及何時運行它。畢竟,Rake可以被視爲將多個Ruby腳本放在一起並在它們之間創建依賴關係的一種便捷方式。如果您認爲機器人周圍會有一些其他任務,而不僅僅是運行它(一些清理,部署等),爲了方便起見,使用Rake會很好。如果還沒有,則重構bot的邏輯,並使用Rake任務對其進行初始化。但是,如果你離開它並且按原樣運行你的腳本(使用monit,你的自定義init.d腳本,ad-hoc等等),它可能會很好。

如果我沒有使用rake運行它(據推測是Monit監測的獨立進程),那麼如何與Resque進行交互或訪問我的rails模型?

耙子對此沒有影響。從操作系統的角度來看,如果您通過Rake運行Resque並通過Rake運行您的機器人或作爲獨立腳本運行,則無關緊要,它們將是不同的進程。另外請記住,Resque需要Redis在某處運行。

我知道這可能是很瑣碎的問題

無可言。我認爲需要一段時間才能解決像這樣微不足道的問題。

0

您可以將您的代碼運行在初始化程序上,並且可以完全訪問所有Rails模型或庫。

這樣,您不需要在bot和Rails應用程序之間「溝通」,因爲您的bot在您的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)