Rabbitmq - 在同一频道上消费和发布?

时间:2014-07-31 22:34:47

标签: python python-2.7 rabbitmq pika

我有两个python进程通过pika连接到Rabbitmq。每个主题都会消耗一组主题,而另一个主题则作为响应发布。一个使用SelectConnection,另一个使用TornadoConnection。

两者目前只是模拟用户和我的服务器之间的对话的测试程序,并且每个程序的on_message()都是硬编码的,以便在收到的routing_key上进行分支并向其发布适当的响应&#39对应的。

最初,在经过一段随机时间后,通常不会超过2分钟,我会收到如下错误:

UnexpectedFrame: Basic.publish: (505) UNEXPECTED_FRAME - expected content header for class 60, got non content header frame instead

在搜索了堆栈溢出和其他地方的大量帖子之后,我已经明白这个错误与在basic_publish完成之前消耗某些东西的竞争条件有关。

我已对代码进行了更改,因此我不会立即执行basic_publish(),而是将回调传递给connection.add_timeout(),延迟时间为1秒。进行此更改后,我已经能够进行多次运行,其中两个进程具有对话"彼此相关> 1小时不重现错误。

我的问题是,这只是一个黑客,只是因为我模拟一个用户?我是否需要有2个独立的渠道供消费和发布?

def on_message(self, unused_channel, basic_deliver, properties, body):
    if self._sibling_app_id == properties.app_id:
        self.dispatch_message(basic_deliver, properties, body)


def dispatch_message(self, basic_deliver, properties, body):
    (user_id, msg_type) = basic_deliver.routing_key.rsplit('.', 1)

    if "login-response" == msg_type:
        print body
    elif "gid-assignment" == msg_type:
        print body
    elif "tutor-logout" == msg_type:
        print body
    elif "tutor-turn" == msg_type:
        message = "i don't know"
        routing_key = "%s.input" % user_id
        callback = self.delayed_publish_message(routing_key, message)
        self.schedule_next_message(callback, 1)
    elif "nlu" == msg_type:
        message = "dnk"
        routing_key = "%s.nlu-response" % user_id
        callback = self.delayed_publish_message(routing_key, message)
        self.schedule_next_message(callback, 1)
    else:
        print "invalid message-type: %s" % msg_type
        print body

def delayed_publish_message(self, routing_key, message):
    """returns a callback which can be passed to schedule_next_message()"""
    def delayed_publish_cb():
        self.publish_message(routing_key, message)
    return delayed_publish_cb


def schedule_next_message(self, cb, publish_interval=None):
    if self._stopping:
        return
    if publish_interval is None:
        publish_interval = self.PUBLISH_INTERVAL
    if -1 == publish_interval:
        return
    self._connection.add_timeout(publish_interval, cb)


def publish_message(self, routing_key, message):
    if self._stopping:
        return
    properties = pika.BasicProperties(app_id=self._app_id,
                                                          content_type='text/plain')
    self._channel.basic_publish(self.EXCHANGE, routing_key,
                                                 message, properties)

2 个答案:

答案 0 :(得分:5)

通道将单向使用。 AMQP protocol specification非常清楚:

  

AMQP会话关联两个单向通道,以形成两个Container之间的双向顺序对话。一个   单个连接可能有多个独立的会话活动   同时,达到协商的频道限制。两个连接   和会话由每个对等体建模为存储本地的端点   关于连接或会话的最后已知远程状态   问题

因此,您应该为您的应用程序使用输入和输出通道。

答案 1 :(得分:1)

我做了我的承诺,准备去睡觉,然后我突然想出来了。我发现在rabbitmq.com上的python教程仍然说安装pika:

 sudo pip install pika==0.9.8

虽然0.9.8在2012年的某个时候出现,但我认为修复版是在发布之后的某个时间添加的。在2013年某个时候发布了0.9.9

所以,我做了:

sudo pip uninstall pika

然后是pika网站上的安装说明:

sudo pip install pika

然后我用basic_publish()替换了我的所有connection.add_timeout(1,delayed_publish_cb),交叉了我的手指,运行它,我的两个进程在不到5分钟内互相交换了大约200,000条消息,没有任何问题

很高兴知道2012年的错误修复仍然有效。

我必须让兔子家伙知道更新他们的教程。