1
0
mirror of synced 2024-11-22 01:13:49 +00:00

Fixed "Index out of range" when publishing from multiple thread (or from a message handler with prefetchcount > 1)

This commit is contained in:
Mark van Renswoude 2019-05-20 15:22:40 +02:00
parent 4c08e9b684
commit 0bd9d06795

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -37,6 +38,9 @@ namespace Tapeti.Connection
private IModel channelInstance; private IModel channelInstance;
private ulong lastDeliveryTag; private ulong lastDeliveryTag;
private DateTime connectedDateTime; private DateTime connectedDateTime;
// These fields must be locked, since the callbacks for BasicAck/BasicReturn can run in a different thread
private readonly object confirmLock = new Object();
private readonly Dictionary<ulong, ConfirmMessageInfo> confirmMessages = new Dictionary<ulong, ConfirmMessageInfo>(); private readonly Dictionary<ulong, ConfirmMessageInfo> confirmMessages = new Dictionary<ulong, ConfirmMessageInfo>();
private readonly Dictionary<string, ReturnInfo> returnRoutingKeys = new Dictionary<string, ReturnInfo>(); private readonly Dictionary<string, ReturnInfo> returnRoutingKeys = new Dictionary<string, ReturnInfo>();
@ -208,6 +212,9 @@ namespace Tapeti.Connection
async (handler, next) => await handler.Handle(context, next), async (handler, next) => await handler.Handle(context, next),
() => taskQueue.Value.Add(async () => () => taskQueue.Value.Add(async () =>
{ {
if (Thread.CurrentThread.ManagedThreadId != 3)
Debug.WriteLine(Thread.CurrentThread.ManagedThreadId);
var body = messageSerializer.Serialize(context.Message, context.Properties); var body = messageSerializer.Serialize(context.Message, context.Properties);
Task<int> publishResultTask = null; Task<int> publishResultTask = null;
@ -225,7 +232,16 @@ namespace Tapeti.Connection
{ {
lastDeliveryTag++; lastDeliveryTag++;
Monitor.Enter(confirmLock);
try
{
confirmMessages.Add(lastDeliveryTag, messageInfo); confirmMessages.Add(lastDeliveryTag, messageInfo);
}
finally
{
Monitor.Exit(confirmLock);
}
publishResultTask = messageInfo.CompletionSource.Task; publishResultTask = messageInfo.CompletionSource.Task;
} }
else else
@ -326,7 +342,17 @@ namespace Tapeti.Connection
if (config.UsePublisherConfirms) if (config.UsePublisherConfirms)
{ {
lastDeliveryTag = 0; lastDeliveryTag = 0;
Monitor.Enter(confirmLock);
try
{
confirmMessages.Clear(); confirmMessages.Clear();
}
finally
{
Monitor.Exit(confirmLock);
}
channelInstance.ConfirmSelect(); channelInstance.ConfirmSelect();
} }
@ -402,6 +428,9 @@ namespace Tapeti.Connection
private void HandleBasicAck(object sender, BasicAckEventArgs e) private void HandleBasicAck(object sender, BasicAckEventArgs e)
{
Monitor.Enter(confirmLock);
try
{ {
foreach (var deliveryTag in GetDeliveryTags(e)) foreach (var deliveryTag in GetDeliveryTags(e))
{ {
@ -421,9 +450,17 @@ namespace Tapeti.Connection
confirmMessages.Remove(deliveryTag); confirmMessages.Remove(deliveryTag);
} }
} }
finally
{
Monitor.Exit(confirmLock);
}
}
private void HandleBasicNack(object sender, BasicNackEventArgs e) private void HandleBasicNack(object sender, BasicNackEventArgs e)
{
Monitor.Enter(confirmLock);
try
{ {
foreach (var deliveryTag in GetDeliveryTags(e)) foreach (var deliveryTag in GetDeliveryTags(e))
{ {
@ -434,6 +471,11 @@ namespace Tapeti.Connection
confirmMessages.Remove(e.DeliveryTag); confirmMessages.Remove(e.DeliveryTag);
} }
} }
finally
{
Monitor.Exit(confirmLock);
}
}
private IEnumerable<ulong> GetDeliveryTags(BasicAckEventArgs e) private IEnumerable<ulong> GetDeliveryTags(BasicAckEventArgs e)