public void Dispatch(MessageDispatch messageDispatch) { // Auto ack messages when we reach 75% of the prefetch deliveredCounter++; if(deliveredCounter > (0.75 * this.info.PrefetchSize)) { try { MessageAck ack = new MessageAck(); ack.AckType = (byte)AckType.ConsumedAck; ack.ConsumerId = messageDispatch.ConsumerId; ack.Destination = messageDispatch.Destination; ack.FirstMessageId = messageDispatch.Message.MessageId; ack.MessageCount = deliveredCounter; this.connection.Oneway(ack); this.deliveredCounter = 0; } catch(Exception e) { this.connection.OnAsyncException(e); } } DestinationInfo destInfo = messageDispatch.Message.DataStructure as DestinationInfo; if(destInfo != null) { ProcessDestinationInfo(destInfo); } else { // This can happen across networks Tracer.Debug("Unexpected message was dispatched to the AdvisoryConsumer: " + messageDispatch); } }
public override Response processMessageAck(MessageAck ack) { if(TrackTransactions && ack != null && ack.TransactionId != null) { ConnectionId connectionId = ack.ConsumerId.ParentId.ParentId; if(connectionId != null) { ConnectionState cs = connectionStates[connectionId]; if(cs != null) { TransactionState transactionState = cs[ack.TransactionId]; if(transactionState != null) { transactionState.addCommand(ack); } } } return TRACKED_RESPONSE_MARKER; } return null; }
public virtual Response processMessageAck(MessageAck ack) { return null; }
internal void SendAck(MessageAck ack) { this.SendAck(ack, false); }
internal void SendAck(MessageAck ack, bool lazy) { if(lazy || connection.SendAcksAsync || this.IsTransacted ) { this.connection.Oneway(ack); } else { this.connection.SyncRequest(ack); } }
private void AckLater(MessageDispatch dispatch, AckType type) { // Don't acknowledge now, but we may need to let the broker know the // consumer got the message to expand the pre-fetch window if(this.session.IsTransacted) { this.session.DoStartTransaction(); if(!synchronizationRegistered) { Tracer.DebugFormat("Consumer {0} Registering new MessageConsumerSynchronization", this.info.ConsumerId); this.synchronizationRegistered = true; this.session.TransactionContext.AddSynchronization(new MessageConsumerSynchronization(this)); } } this.deliveredCounter++; MessageAck oldPendingAck = pendingAck; pendingAck = new MessageAck(); pendingAck.AckType = (byte) type; pendingAck.ConsumerId = this.info.ConsumerId; pendingAck.Destination = dispatch.Destination; pendingAck.LastMessageId = dispatch.Message.MessageId; pendingAck.MessageCount = deliveredCounter; if(this.session.IsTransacted && this.session.TransactionContext.InTransaction) { pendingAck.TransactionId = this.session.TransactionContext.TransactionId; } if(oldPendingAck == null) { pendingAck.FirstMessageId = pendingAck.LastMessageId; } else if(oldPendingAck.AckType == pendingAck.AckType) { pendingAck.FirstMessageId = oldPendingAck.FirstMessageId; } else { // old pending ack being superseded by ack of another type, if is is not a delivered // ack and hence important, send it now so it is not lost. if(oldPendingAck.AckType != (byte) AckType.DeliveredAck) { if(Tracer.IsDebugEnabled) { Tracer.Debug("Sending old pending ack " + oldPendingAck + ", new pending: " + pendingAck); } this.session.Connection.Oneway(oldPendingAck); } else { if(Tracer.IsDebugEnabled) { Tracer.Debug("dropping old pending ack " + oldPendingAck + ", new pending: " + pendingAck); } } } if((0.5 * this.info.PrefetchSize) <= (this.deliveredCounter - this.additionalWindowSize)) { this.session.Connection.Oneway(pendingAck); this.pendingAck = null; this.deliveredCounter = 0; this.additionalWindowSize = 0; } }
internal void Acknowledge() { lock(this.dispatchedMessages) { // Acknowledge all messages so far. MessageAck ack = MakeAckForAllDeliveredMessages(AckType.ConsumedAck); if(ack == null) { return; // no msgs } if(this.session.IsTransacted) { if (!this.session.TransactionContext.InTransaction) { this.session.DoStartTransaction(); } ack.TransactionId = this.session.TransactionContext.TransactionId; } this.session.SendAck(ack); this.pendingAck = null; // Adjust the counters this.deliveredCounter = Math.Max(0, this.deliveredCounter - this.dispatchedMessages.Count); this.additionalWindowSize = Math.Max(0, this.additionalWindowSize - this.dispatchedMessages.Count); if(!this.session.IsTransacted) { this.dispatchedMessages.Clear(); } } }
private MessageAck MakeAckForAllDeliveredMessages(AckType type) { lock(this.dispatchedMessages) { if(this.dispatchedMessages.Count == 0) { return null; } MessageDispatch dispatch = this.dispatchedMessages.First.Value; MessageAck ack = new MessageAck(); ack.AckType = (byte) type; ack.ConsumerId = this.info.ConsumerId; ack.Destination = dispatch.Destination; ack.LastMessageId = dispatch.Message.MessageId; ack.MessageCount = this.dispatchedMessages.Count; ack.FirstMessageId = this.dispatchedMessages.Last.Value.Message.MessageId; return ack; } }
public virtual void Dispatch(MessageDispatch dispatch) { MessageListener listener = this.listener; bool dispatchMessage = false; try { lock(this.unconsumedMessages.SyncRoot) { if(this.clearDispatchList) { // we are reconnecting so lets flush the in progress messages this.clearDispatchList = false; this.unconsumedMessages.Clear(); if(this.pendingAck != null && this.pendingAck.AckType == (byte) AckType.DeliveredAck) { // on resumption a pending delivered ack will be out of sync with // re-deliveries. if(Tracer.IsDebugEnabled) { Tracer.Debug("removing pending delivered ack on transport interupt: " + pendingAck); } this.pendingAck = null; } } if(!this.unconsumedMessages.Closed) { if(listener != null && this.unconsumedMessages.Running) { dispatchMessage = true; } else { this.unconsumedMessages.Enqueue(dispatch); } } } if(dispatchMessage) { ActiveMQMessage message = CreateActiveMQMessage(dispatch); this.BeforeMessageIsConsumed(dispatch); try { bool expired = (!IgnoreExpiration && message.IsExpired()); if(!expired) { listener(message); } this.AfterMessageIsConsumed(dispatch, expired); } catch(Exception e) { if(IsAutoAcknowledgeBatch || IsAutoAcknowledgeEach || IsIndividualAcknowledge) { // Redeliver the message Rollback(); } else { // Transacted or Client ack: Deliver the next message. this.AfterMessageIsConsumed(dispatch, false); } Tracer.Error(this.info.ConsumerId + " Exception while processing message: " + e); // If aborted we stop the abort here and let normal processing resume. // This allows the session to shutdown normally and ack all messages // that have outstanding acks in this consumer. if((Thread.CurrentThread.ThreadState & ThreadState.AbortRequested) == ThreadState.AbortRequested) { Thread.ResetAbort(); } } } if(++dispatchedCount % 1000 == 0) { dispatchedCount = 0; Thread.Sleep(1); } } catch(Exception e) { this.session.Connection.OnSessionException(this.session, e); } }
public void DeliverAcks() { MessageAck ack = null; if(this.deliveringAcks.CompareAndSet(false, true)) { if(this.IsAutoAcknowledgeEach) { lock(this.dispatchedMessages) { ack = MakeAckForAllDeliveredMessages(AckType.DeliveredAck); if(ack != null) { Tracer.Debug("Consumer - DeliverAcks clearing the Dispatch list"); this.dispatchedMessages.Clear(); } else { ack = this.pendingAck; this.pendingAck = null; } } } else if(pendingAck != null && pendingAck.AckType == (byte) AckType.ConsumedAck) { ack = pendingAck; pendingAck = null; } if(ack != null) { MessageAck ackToSend = ack; try { this.session.SendAck(ackToSend); } catch(Exception e) { Tracer.DebugFormat("{0} : Failed to send ack, {1}", this.info.ConsumerId, e); } } else { this.deliveringAcks.Value = false; } } }
protected void DoIndividualAcknowledge(ActiveMQMessage message) { MessageDispatch dispatch = null; lock(this.dispatchedMessages) { foreach(MessageDispatch originalDispatch in this.dispatchedMessages) { if(originalDispatch.Message.MessageId.Equals(message.MessageId)) { dispatch = originalDispatch; this.dispatchedMessages.Remove(originalDispatch); break; } } } if(dispatch == null) { Tracer.DebugFormat("Attempt to Ack MessageId[{0}] failed because the original dispatch is not in the Dispatch List", message.MessageId); return; } MessageAck ack = new MessageAck(); ack.AckType = (byte) AckType.IndividualAck; ack.ConsumerId = this.info.ConsumerId; ack.Destination = dispatch.Destination; ack.LastMessageId = dispatch.Message.MessageId; ack.MessageCount = 1; Tracer.Debug("Sending Individual Ack for MessageId: " + ack.LastMessageId.ToString()); this.session.SendAck(ack); }
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); } }