RabbitMQ Wait for a message with a timeout和Wait for a single RabbitMQ message with a timeout中的解决方案似乎无法正常工作,因为官方C#库中没有下一个交付方法,并且QueueingBasicConsumer已被删除,因此它只会在任何地方抛出NotSupportedException。
如何从队列中等待指定超时的单个消息?
PS
可以通过Basic.Get()完成,是的,但是,在指定的时间间隔(超额流量,超额CPU)中提取消息是不好的解决方案。
更新
通过implmenetationEventingBasicConsumer 不支持立即取消。即使您在某个时刻调用 BasicCancel ,即使您通过 BasicQos 指定预取 - 它仍然会在 Frames 中获取,并且这些帧可以包含多个消息。因此,单个任务执行并不好。不要打扰 - 它只是不能处理单个消息。
答案 0 :(得分:7)
有很多方法可以做到这一点。例如,您可以将EventingBasicConsumer
与ManualResetEvent
一起使用,就像这样(仅用于演示目的 - 更好地使用以下方法之一):
var factory = new ConnectionFactory();
using (var connection = factory.CreateConnection()) {
using (var channel = connection.CreateModel()) {
// setup signal
using (var signal = new ManualResetEvent(false)) {
var consumer = new EventingBasicConsumer(channel);
byte[] messageBody = null;
consumer.Received += (sender, args) => {
messageBody = args.Body;
// process your message or store for later
// set signal
signal.Set();
};
// start consuming
channel.BasicConsume("your.queue", false, consumer);
// wait until message is received or timeout reached
bool timeout = !signal.WaitOne(TimeSpan.FromSeconds(10));
// cancel subscription
channel.BasicCancel(consumer.ConsumerTag);
if (timeout) {
// timeout reached - do what you need in this case
throw new Exception("timeout");
}
// at this point messageBody is received
}
}
}
正如您在评论中所述 - 如果您希望同一队列中有多条消息,那么这不是最佳方式。在任何情况下,它都不是最好的方式,我只是为了证明ManualResetEvent
的使用,以防案件库本身不提供超时支持。
如果您正在执行RPC(远程过程调用,请求 - 回复) - 您可以在服务器端使用SimpleRpcClient
和SimpleRpcServer
。客户端将如下所示:
var client = new SimpleRpcClient(channel, "your.queue");
client.TimeoutMilliseconds = 10 * 1000;
client.TimedOut += (sender, args) => {
// do something on timeout
};
var reply = client.Call(myMessage); // will return reply or null if timeout reached
更简单的方法:使用基本的Subscription
类(它在内部使用相同的EventingBasicConsumer
,但支持超时,因此您不需要自己实现),如下所示:
var sub = new Subscription(channel, "your.queue");
BasicDeliverEventArgs reply;
if (!sub.Next(10 * 1000, out reply)) {
// timeout
}