Inheritance: BaseCommand
Example #1
0
        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;
 }
Example #4
0
 internal void SendAck(MessageAck ack)
 {
     this.SendAck(ack, false);
 }
Example #5
0
 internal void SendAck(MessageAck ack, bool lazy)
 {
     if(lazy || connection.SendAcksAsync || this.IsTransacted )
     {
         this.connection.Oneway(ack);
     }
     else
     {
         this.connection.SyncRequest(ack);
     }
 }
Example #6
0
		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;
			}
		}
Example #7
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();
				}
			}
		}
Example #8
0
		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;
			}
		}
Example #9
0
		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);
			}
		}
Example #10
0
		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;
				}
			}
		}
Example #11
0
		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);
		}
Example #12
0
		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);
			}
		}