[英]How can I have my RabbitMQ consumer receive just one message without it timing-out and sending agan?
我們有一個問題,如果一條消息處理時間過長,它會從未確認回到就緒狀態,然后再次發送。 有沒有辦法防止這種情況?
我們有一個這樣初始化的隊列消費者 class:
private void Initialize()
{
string queueName = _configuration["QueueName"] + _configuration["QueueNameSuffixForSubscriber"];
var factory = CreateConnectionFactory();
var connection = factory.CreateConnection();
_channel = connection.CreateModel();
// The message TTL must match for QueueDeclare() to work.
var arguments = new Dictionary<string, object>();
arguments.Add("x-message-ttl", Convert.ToInt32(_configuration["EventBusMessageTtl"]));
// By default, RabbitMQ dispatches all the messages to the first consumer. You can change this behaviour by
// setting the BasicQos, this controls the no of messages a consumer can receive before it acknowledges it.
_channel.BasicQos(0, 1, false);
_channel.QueueDeclare(queue: queueName, durable: true, exclusive: false, autoDelete: false, arguments: arguments);
var consumer = new EventingBasicConsumer(_channel);
consumer.Received += ConsumerReceived;
_channel.BasicConsume(queue: queueName, autoAck: false, consumer: consumer);
}
注意這一行:
_channel.BasicQos(0, 1, false);
這就是我們的消費者一次只提取一條消息的方式。 但是,如果該消息在發送 ack 之前花費的時間超過 2 分鍾,RMQ 將再次發送該消息。 我們不希望這樣。 (處理時間幾乎不會超過 2 分鍾,但我們不想滿足於差不多.)
有沒有辦法阻止 RMQ 再次發送消息? 我可以在處理消息之前發送 ack,但是我們會立即收到下一條消息,我們也不希望這樣。 我們希望在接受下一條消息之前等待消息完成處理。
如果我們可以在准備好時從 RMQ 中提取,那將解決它。
這是ConsumerReceived()
方法:
private void ConsumerReceived(object model, BasicDeliverEventArgs eventArgs)
{
try
{
var message = Encoding.UTF8.GetString(eventArgs.Body.ToArray());
InvokeHandlers(eventArgs, message);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error occurred in processing message or invoking handlers.");
}
finally
{
_channel.BasicAck(eventArgs.DeliveryTag, false);
}
}
我同意這似乎是輪詢而不是消費者訂閱的理想流程。 通常,您不想輪詢,因為它極大地損害了吞吐量,但在您的情況下,這正是您想要的。
while (true)
{
BasicGetResult result = channel.BasicGet(queueName, noAck);
if (result == null)
{
// No message available at this time.
// Sleep/delay to avoid cpu and I/O churn
Thread.Sleep(2000);
}
else
{
try
{
IBasicProperties props = result.BasicProperties;
var message = Encoding.UTF8.GetString(result.Body.ToArray());
InvokeHandlers(eventArgs, message);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error occurred in processing message or invoking handlers.");
}
finally
{
_channel.BasicAck(eventArgs.DeliveryTag, false);
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.