我正在构建一个基本上允许用户与机器人聊天的服务,然后机器人会对用户发送的聊天进行一些奇怪的处理,并最终回复一些有意义的数据。基本上类似于Aardvark使用(?)工作的方式。
我的机器人正在工作,现在正在聆听,而且我有一个单独的rails应用程序将执行所有其他繁重的工作。这两个部分都是单独工作的,现在我仍然坚持两者的接口。我的想法是通过Resque将机器人(基本上是一个小的ruby脚本)与rails应用程序连接 - 任何进入队列的东西,被拾取,结果然后再次推回到队列,然后脚本会回复结果。
我不清楚如何建立这个界面:
我知道这些可能是非常微不足道的问题,但我很难理解哪个更好,以及如何进行设置。
答案 0 :(得分:4)
您的Rails应用程序和此僵尸程序守护程序之间有三种通信方式:
当您将Resque作业从各种作业队列中排除并拔出时,您只需通过API读取/写入共享的Redis数据库。 bot和Rails应用程序都通过网络与Redis DB进行通信。
我建议直接运行僵尸程序作为由monit管理的ruby进程或rake任务。听起来你已经知道如何做到这一点。
答案 1 :(得分:2)
我认为这里的主要问题是你需要另一种消息传递解决方案(类似于IPC,而不是IM),而不是试图弯曲“只是”队列的Resque。一些选项是amqp gem(AMQP协议)或zmq gem(ZeroMQ协议),但您也可以通过Ruby标准库Socket类(good examples)使用普通的旧UNIX套接字。它们都有不同的优点和缺点,所以它可能取决于你。
然后,交互可能看起来像这样:
可以像往常一样进行一些更改。例如,我认为你根本不需要Resque。机器人可以简单地将请求立即传递给Rails应用程序,但它取决于负载,您想要实现的响应时间,当前架构等。也许Resque作业可以等待Rails应用程序返回结果然后工作(不是Rails应用程序)会使用IPC。还有其他变化...
我是否需要编写一个rake任务来启动/停止/重新加载bot
不,你没有。这取决于你如何以及何时运行它。毕竟,Rake可以被视为将多个Ruby脚本放在一起并在它们之间创建依赖关系的便捷方式。如果你认为机器人周围会有一些其他任务而不仅仅是运行它(一些清理,部署等),为方便起见,使用Rake会很好。如果还没有,重构机器人的逻辑,并使用Rake任务来初始化它。但是如果你离开它并且只是按原样运行你的脚本(使用monit,你的自定义init.d脚本,ad-hoc等)可能会没问题。
如果我在没有rake的情况下运行它(据说是由Monit监控的独立进程),那么我该如何与Resque接口或访问我的rails模型?
耙子对此没有影响。从操作系统的角度来看,如果您通过Rake运行Resque并通过Rake运行bot或作为独立脚本运行,则无关紧要,无论如何它们都将是不同的进程。还要记住,Resque需要Redis才能在某个地方运行。
我知道这些可能是非常微不足道的问题
一点也不。我认为这样的问题需要一段时间才能被认为是微不足道的。
答案 2 :(得分:0)
您可以将代码放在初始化程序上,并拥有对所有Rails模型或库的完全访问权限。
这样,您无需在机器人和Rails应用程序之间进行“通信”,因为您的机器人位于Rails应用程序中。
Boilerplate代码如下:
配置/初始化/ 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)