我想向RabbitMQ服务器发送消息,然后等待回复消息(在“回复”队列中)。当然,我不想永远等待处理这些消息的应用程序关闭 - 需要超时。这听起来像是一项非常基本的任务,但我找不到办法。我现在遇到py-amqplib和RabbitMQ .NET client的问题。
到目前为止,我得到的最佳解决方案是使用basic_get
与sleep
之间进行投票,但这非常难看:
def _wait_for_message_with_timeout(channel, queue_name, timeout):
slept = 0
sleep_interval = 0.1
while slept < timeout:
reply = channel.basic_get(queue_name)
if reply is not None:
return reply
time.sleep(sleep_interval)
slept += sleep_interval
raise Exception('Timeout (%g seconds) expired while waiting for an MQ response.' % timeout)
当然有更好的方法吗?
答案 0 :(得分:8)
这是我最终在.NET客户端中所做的事情:
protected byte[] WaitForMessageWithTimeout(string queueName, int timeoutMs)
{
var consumer = new QueueingBasicConsumer(Channel);
var tag = Channel.BasicConsume(queueName, true, null, consumer);
try
{
object result;
if (!consumer.Queue.Dequeue(timeoutMs, out result))
throw new ApplicationException(string.Format("Timeout ({0} seconds) expired while waiting for an MQ response.", timeoutMs / 1000.0));
return ((BasicDeliverEventArgs)result).Body;
}
finally
{
Channel.BasicCancel(tag);
}
}
不幸的是,我无法对py-amqplib执行相同的操作,因为除非您调用basic_consume
并且channel.wait()
不支持超时,否则channel.wait()
方法不会调用回调!这种愚蠢的限制(我一直在遇到)意味着如果你从未收到另一条消息,你的线程将永远冻结。
答案 1 :(得分:8)
我刚刚在amqplib
中添加了对carrot
的超时支持。
这是amqplib.client0_8.Connection
:
http://github.com/ask/carrot/blob/master/carrot/backends/pyamqplib.py#L19-97
wait_multi
是能够以任意数字接收的channel.wait
版本
渠道。
我想这可能会在某个时刻合并到上游。
答案 2 :(得分:2)
答案 3 :(得分:1)
这似乎打破了异步处理的整个想法,但如果你必须我认为正确的方法是使用RpcClient。
答案 4 :(得分:1)
Rabbit现在允许您添加超时事件。只需将代码包装在try catch中,然后在TimeOut和Disconnect处理程序中抛出异常:
try{
using (IModel channel = rabbitConnection.connection.CreateModel())
{
client = new SimpleRpcClient(channel, "", "", queue);
client.TimeoutMilliseconds = 5000; // 5 sec. defaults to infinity
client.TimedOut += RpcTimedOutHandler;
client.Disconnected += RpcDisconnectedHandler;
byte[] replyMessageBytes = client.Call(message);
return replyMessageBytes;
}
}
catch (Exception){
//Handle timeout and disconnect here
}
private void RpcDisconnectedHandler(object sender, EventArgs e)
{
throw new Exception("RPC disconnect exception occured.");
}
private void RpcTimedOutHandler(object sender, EventArgs e)
{
throw new Exception("RPC timeout exception occured.");
}