예제 #1
0
        /// <summary>
        /// Process pull request and sends queue message to requester as response
        /// </summary>
        private async Task <bool> ProcessPull(QueueClient requester, HorseMessage request, QueueMessage message, IList <KeyValuePair <string, string> > headers)
        {
            //if we need acknowledge, we are sending this information to receivers that we require response
            message.Message.WaitResponse = _queue.Options.Acknowledge != QueueAckDecision.None;

            //if we need acknowledge from receiver, it has a deadline.
            DateTime?deadline = null;

            if (_queue.Options.Acknowledge != QueueAckDecision.None)
            {
                deadline = DateTime.UtcNow.Add(_queue.Options.AcknowledgeTimeout);
            }

            //if to process next message is requires previous message acknowledge, wait here
            if (_queue.Options.Acknowledge == QueueAckDecision.WaitForAcknowledge)
            {
                await _queue.WaitForAcknowledge(message);
            }

            if (message.CurrentDeliveryReceivers.Count > 0)
            {
                message.CurrentDeliveryReceivers.Clear();
            }

            message.Decision = await _queue.DeliveryHandler.BeginSend(_queue, message);

            if (!await _queue.ApplyDecision(message.Decision, message))
            {
                return(false);
            }

            //call before send and check decision
            message.Decision = await _queue.DeliveryHandler.CanConsumerReceive(_queue, message, requester.Client);

            if (!await _queue.ApplyDecision(message.Decision, message))
            {
                return(false);
            }

            //create delivery object
            MessageDelivery delivery = new MessageDelivery(message, requester, deadline);
            bool            sent     = await requester.Client.SendAsync(message.Message, headers);

            if (sent)
            {
                message.CurrentDeliveryReceivers.Add(requester);
                _queue.TimeKeeper.AddAcknowledgeCheck(delivery);
                delivery.MarkAsSent();

                //do after send operations for per message
                _queue.Info.AddDelivery();
                message.Decision = await _queue.DeliveryHandler.ConsumerReceived(_queue, delivery, requester.Client);

                //after all sending operations completed, calls implementation send completed method and complete the operation
                _queue.Info.AddMessageSend();

                if (!await _queue.ApplyDecision(message.Decision, message))
                {
                    return(false);
                }
            }
            else
            {
                message.Decision = await _queue.DeliveryHandler.ConsumerReceiveFailed(_queue, delivery, requester.Client);

                if (!await _queue.ApplyDecision(message.Decision, message))
                {
                    return(false);
                }
            }

            message.Decision = await _queue.DeliveryHandler.EndSend(_queue, message);

            await _queue.ApplyDecision(message.Decision, message);

            if (message.Decision.Allow && message.Decision.PutBack == PutBackDecision.No)
            {
                _queue.Info.AddMessageRemove();
                _ = _queue.DeliveryHandler.MessageDequeued(_queue, message);
            }

            return(true);
        }
예제 #2
0
        private async Task <PushResult> ProcessMessage(QueueMessage message)
        {
            //if we need acknowledge from receiver, it has a deadline.
            DateTime?ackDeadline = null;

            if (_queue.Options.Acknowledge != QueueAckDecision.None)
            {
                ackDeadline = DateTime.UtcNow.Add(_queue.Options.AcknowledgeTimeout);
            }

            //if to process next message is requires previous message acknowledge, wait here
            if (_queue.Options.Acknowledge == QueueAckDecision.WaitForAcknowledge)
            {
                await _queue.WaitForAcknowledge(message);
            }

            //if there are not receivers, complete send operation
            List <QueueClient> clients = _queue.ClientsClone;

            if (clients.Count == 0)
            {
                _queue.AddMessage(message, false);
                return(PushResult.NoConsumers);
            }

            if (message.CurrentDeliveryReceivers.Count > 0)
            {
                message.CurrentDeliveryReceivers.Clear();
            }

            message.Decision = await _queue.DeliveryHandler.BeginSend(_queue, message);

            if (!await _queue.ApplyDecision(message.Decision, message))
            {
                return(PushResult.Success);
            }

            //create prepared message data
            byte[] messageData = HmqWriter.Create(message.Message);

            Decision final         = new Decision(false, false, PutBackDecision.No, DeliveryAcknowledgeDecision.None);
            bool     messageIsSent = false;

            //to all receivers
            foreach (QueueClient client in clients)
            {
                //to only online receivers
                if (!client.Client.IsConnected)
                {
                    continue;
                }

                //call before send and check decision
                Decision ccrd = await _queue.DeliveryHandler.CanConsumerReceive(_queue, message, client.Client);

                final = HorseQueue.CreateFinalDecision(final, ccrd);

                if (!ccrd.Allow)
                {
                    continue;
                }

                //create delivery object
                MessageDelivery delivery = new MessageDelivery(message, client, ackDeadline);

                //send the message
                bool sent = await client.Client.SendAsync(messageData);

                if (sent)
                {
                    if (_queue.Options.Acknowledge != QueueAckDecision.None)
                    {
                        client.CurrentlyProcessing = message;
                        client.ProcessDeadline     = ackDeadline ?? DateTime.UtcNow;
                    }

                    messageIsSent = true;
                    message.CurrentDeliveryReceivers.Add(client);

                    //adds the delivery to time keeper to check timing up
                    _queue.TimeKeeper.AddAcknowledgeCheck(delivery);

                    //mark message is sent
                    delivery.MarkAsSent();

                    //do after send operations for per message
                    _queue.Info.AddDelivery();
                    Decision d = await _queue.DeliveryHandler.ConsumerReceived(_queue, delivery, client.Client);

                    final = HorseQueue.CreateFinalDecision(final, d);
                }
                else
                {
                    Decision d = await _queue.DeliveryHandler.ConsumerReceiveFailed(_queue, delivery, client.Client);

                    final = HorseQueue.CreateFinalDecision(final, d);
                }
            }

            message.Decision = final;
            if (!await _queue.ApplyDecision(final, message))
            {
                return(PushResult.Success);
            }

            //after all sending operations completed, calls implementation send completed method and complete the operation
            if (messageIsSent)
            {
                _queue.Info.AddMessageSend();
            }

            message.Decision = await _queue.DeliveryHandler.EndSend(_queue, message);

            await _queue.ApplyDecision(message.Decision, message);

            if (message.Decision.Allow && message.Decision.PutBack == PutBackDecision.No)
            {
                _queue.Info.AddMessageRemove();
                _ = _queue.DeliveryHandler.MessageDequeued(_queue, message);
            }

            return(PushResult.Success);
        }