我正在使用RabbitMQ .NET客户端,当网络断开连接时,我们的服务正在丢失消息。 我试图编写一个测试应用程序并使用“BasicAcks”事件,并重新发送断开连接时未收到确认的每条消息,但它仍然丢失消息。使用ConnectionShutdown事件检测断开连接(查找ReplyCode“451”)。 要检查收到的消息,我会使用它们并读取内容,该内容应至少包含0到49999之间的每个数字。 当网络稳定时,它可以正常工作。在模拟不稳定的网络(禁用网络适配器)时,有时会丢失数百条消息。
以下是代码:
private static ConcurrentQueue<byte[]> sendQueue = new ConcurrentQueue<byte[]>();
private static ConcurrentDictionary<ulong, byte[]> waitingForAck = new ConcurrentDictionary<ulong, byte[]>();
private static bool stop;
private static void Main()
{
var server = "192.168.1.123";
var userName = "rabbitmq";
var password = "rabbitmq";
var sendCount = 50000;
try
{
Task.Run(() => Send(server, userName, password, "TestExchange", sendCount));
Task.Run(() =>
{
while (true)
{
Console.WriteLine("Total sent:{0}", totalPackages.Count);
Console.WriteLine("Packages waiting in send queue:{0}", sendQueue.Count);
Console.WriteLine("Packages waiting for ack:{0}", waitingForAck.Count);
Console.WriteLine();
if (stop)
{
break;
}
Thread.Sleep(1000);
}
});
Console.ReadLine();
stop = true;
}
catch (Exception exception)
{
Console.WriteLine("Exception: {0}", exception.Message);
}
Console.ReadLine();
}
public static void Send(string server, string userName, string password, string exchangeName, int sendCount)
{
for (int i = 0; i < sendCount; i++)
{
var content = String.Format("Hello World: {0}", i);
var data = Encoding.UTF8.GetBytes(content);
sendQueue.Enqueue(data);
}
var factory = new ConnectionFactory { HostName = server, UserName = userName, Password = password };
factory.AutomaticRecoveryEnabled = true;
using (var connection = factory.CreateConnection())
{
connection.ConnectionShutdown += Connection_ConnectionShutdown;
using (var channel = connection.CreateModel())
{
channel.ExchangeDeclare(exchangeName, ExchangeType.Fanout, false, false, null);
channel.ConfirmSelect();
channel.BasicAcks += Channel_BasicAcks;
while (!stop)
{
byte[] data;
if (!sendQueue.TryDequeue(out data))
{
Thread.Sleep(100);
continue;
}
if (data == null)
{
continue;
}
var publishTag = channel.NextPublishSeqNo;
try
{
if (!waitingForAck.TryAdd(publishTag, data))
{
Console.WriteLine("Cannot prepare {0}", publishTag);
}
channel.BasicPublish(exchangeName, string.Empty, null, data);
totalPackages.Enqueue(data);
}
catch (Exception)
{
byte[] ignored;
if (!waitingForAck.TryRemove(publishTag, out ignored))
{
Console.WriteLine("cannot delete - exception");
}
Console.WriteLine("Requeue {0}", publishTag);
sendQueue.Enqueue(data);
Thread.Sleep(1000);
continue;
}
}
while (waitingForAck.Count > 0)
{
Thread.Sleep(1000);
Console.WriteLine("Waiting for missing acks");
}
}
}
}
private static void Channel_BasicAcks(object sender, BasicAckEventArgs e)
{
byte[] ignored;
if (e.Multiple)
{
var ids = waitingForAck.Keys.Where(x => x <= e.DeliveryTag).ToArray();
foreach (var id in ids)
{
if (!waitingForAck.TryRemove(id, out ignored))
{
Console.WriteLine("cannot delete {0}", id);
}
}
}
else
{
if (!waitingForAck.TryRemove(e.DeliveryTag, out ignored))
{
Console.WriteLine("cannot delete {0}", e.DeliveryTag);
}
}
}
private static void Connection_ConnectionShutdown(object sender, ShutdownEventArgs e)
{
if (e.ReplyCode == 541)
{
var temp = waitingForAck.Values.ToList();
waitingForAck.Clear();
Console.WriteLine("Connection lost, requeue {0} messages", temp.Count);
foreach (var message in temp)
{
sendQueue.Enqueue(message);
}
}
}
有人能告诉我我做错了吗?
答案 0 :(得分:0)
答案 1 :(得分:0)
好的,问题不在于发送部分,而是接收部分。我在每封邮件sort_values
上面的代码工作正常,所有消息至少发送一次。