private void Rollback()
{
lock(this.unconsumedMessages.SyncRoot)
{
lock(this.dispatchedMessages)
{
if(this.dispatchedMessages.Count == 0)
{
Tracer.DebugFormat("Consumer {0} Rolled Back, no dispatched Messages",
this.info.ConsumerId);
return;
}
// Only increase the redelivery delay after the first redelivery..
MessageDispatch lastMd = this.dispatchedMessages.First.Value;
int currentRedeliveryCount = lastMd.Message.RedeliveryCounter;
redeliveryDelay = this.redeliveryPolicy.RedeliveryDelay(currentRedeliveryCount);
MessageId firstMsgId = this.dispatchedMessages.Last.Value.Message.MessageId;
foreach(MessageDispatch dispatch in this.dispatchedMessages)
{
// Allow the message to update its internal to reflect a Rollback.
dispatch.Message.OnMessageRollback();
}
if(this.redeliveryPolicy.MaximumRedeliveries >= 0 &&
lastMd.Message.RedeliveryCounter > this.redeliveryPolicy.MaximumRedeliveries)
{
// We need to NACK the messages so that they get sent to the DLQ.
MessageAck ack = new MessageAck();
ack.AckType = (byte) AckType.PoisonAck;
ack.ConsumerId = this.info.ConsumerId;
ack.Destination = lastMd.Destination;
ack.LastMessageId = lastMd.Message.MessageId;
ack.MessageCount = this.dispatchedMessages.Count;
ack.FirstMessageId = firstMsgId;
this.session.SendAck(ack);
// Adjust the window size.
additionalWindowSize = Math.Max(0, this.additionalWindowSize - this.dispatchedMessages.Count);
this.redeliveryDelay = 0;
}
else
{
// We only send a RedeliveryAck after the first redelivery
if(currentRedeliveryCount > 0)
{
MessageAck ack = new MessageAck();
ack.AckType = (byte) AckType.RedeliveredAck;
ack.ConsumerId = this.info.ConsumerId;
ack.Destination = lastMd.Destination;
ack.LastMessageId = lastMd.Message.MessageId;
ack.MessageCount = this.dispatchedMessages.Count;
ack.FirstMessageId = firstMsgId;
this.session.SendAck(ack);
}
// stop the delivery of messages.
this.unconsumedMessages.Stop();
if(Tracer.IsDebugEnabled)
{
Tracer.DebugFormat("Consumer {0} Rolled Back, Re-enque {1} messages",
this.info.ConsumerId, this.dispatchedMessages.Count);
}
foreach(MessageDispatch dispatch in this.dispatchedMessages)
{
this.unconsumedMessages.EnqueueFirst(dispatch);
}
if(redeliveryDelay > 0 && !this.unconsumedMessages.Closed)
{
DateTime deadline = DateTime.Now.AddMilliseconds(redeliveryDelay);
ThreadPool.QueueUserWorkItem(this.RollbackHelper, deadline);
}
else
{
Start();
}
}
this.deliveredCounter -= this.dispatchedMessages.Count;
this.dispatchedMessages.Clear();
}
}
// Only redispatch if there's an async listener otherwise a synchronous
// consumer will pull them from the local queue.
if(this.listener != null)
{
this.session.Redispatch(this.unconsumedMessages);
}
}