/// <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); }
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); }