/// <summary> /// Start to process all pending messages. /// This method is called after a client is subscribed to the queue. /// </summary> private async Task ProcessPendingMessages(bool high) { while (State.TriggerSupported) { QueueMessage message; if (high) { lock (HighPriorityLinkedList) { if (HighPriorityLinkedList.Count == 0) { return; } message = HighPriorityLinkedList.First.Value; HighPriorityLinkedList.RemoveFirst(); message.IsInQueue = false; } } else { lock (RegularLinkedList) { if (RegularLinkedList.Count == 0) { return; } message = RegularLinkedList.First.Value; RegularLinkedList.RemoveFirst(); message.IsInQueue = false; } } try { PushResult pr = await State.Push(message); if (pr == PushResult.Empty || pr == PushResult.NoConsumers) { return; } } catch (Exception ex) { Info.AddError(); try { Decision decision = await DeliveryHandler.ExceptionThrown(this, message, ex); await ApplyDecision(decision, message); } catch //if developer does wrong operation, we should not stop { } } } }
/// <summary> /// Start to process all pending messages. /// This method is called after a client is subscribed to the queue. /// </summary> private async Task ProcessPendingMessages(bool high) { while (State.TriggerSupported) { if (_clients.Count == 0) { return; } QueueMessage message; if (high) { lock (PriorityMessagesList) { if (PriorityMessagesList.Count == 0) { return; } message = PriorityMessagesList.First?.Value; if (message == null) { return; } PriorityMessagesList.RemoveFirst(); message.IsInQueue = false; } } else { lock (MessagesList) { if (MessagesList.Count == 0) { return; } message = MessagesList.First?.Value; if (message == null) { return; } MessagesList.RemoveFirst(); message.IsInQueue = false; } } try { PushResult pr = await State.Push(message); if (pr == PushResult.NoConsumers || pr == PushResult.Empty) { return; } } catch (Exception ex) { Server.SendError("PROCESS_MESSAGES", ex, $"QueueName:{Name}"); Info.AddError(); try { Decision decision = await DeliveryHandler.ExceptionThrown(this, message, ex); await ApplyDecision(decision, message); } catch //if developer does wrong operation, we should not stop { } } if (Options.DelayBetweenMessages > 0) { await Task.Delay(Options.DelayBetweenMessages); } } }
/// <summary> /// Pushes a message into the queue. /// </summary> internal async Task <PushResult> Push(QueueMessage message, MqClient sender) { if (Status == QueueStatus.Stopped) { return(PushResult.StatusNotSupported); } if (Options.MessageLimit > 0 && HighPriorityLinkedList.Count + RegularLinkedList.Count >= Options.MessageLimit) { return(PushResult.LimitExceeded); } if (Options.MessageSizeLimit > 0 && message.Message.Length > Options.MessageSizeLimit) { return(PushResult.LimitExceeded); } //prepare properties message.Message.FirstAcquirer = true; message.Message.AcknowledgeRequired = Options.RequestAcknowledge; //if message doesn't have message id and "UseMessageId" option is enabled, create new message id for the message if (Options.UseMessageId && string.IsNullOrEmpty(message.Message.MessageId)) { message.Message.SetMessageId(Channel.Server.MessageIdGenerator.Create()); } //if we have an option maximum wait duration for message, set it after message joined to the queue. //time keeper will check this value and if message time is up, it will remove message from the queue. if (Options.MessageTimeout > TimeSpan.Zero) { message.Deadline = DateTime.UtcNow.Add(Options.MessageTimeout); } if (Options.HideClientNames) { message.Message.SetSource(null); } try { //fire message receive event Info.AddMessageReceive(); Decision decision = await DeliveryHandler.ReceivedFromProducer(this, message, sender); message.Decision = decision; bool allow = await ApplyDecision(decision, message); if (!allow) { return(PushResult.Success); } if (State.CanEnqueue(message)) { await RunInListSync(() => AddMessage(message)); if (State.TriggerSupported && !_triggering) { _ = Trigger(); } } else { _ = State.Push(message); } return(PushResult.Success); } catch (Exception ex) { Info.AddError(); try { Decision decision = await DeliveryHandler.ExceptionThrown(this, State.ProcessingMessage, ex); if (State.ProcessingMessage != null) { await ApplyDecision(decision, State.ProcessingMessage); if (decision.KeepMessage && !State.ProcessingMessage.IsInQueue) { AddMessage(State.ProcessingMessage, false); } } } catch //if developer does wrong operation, we should not stop { } } return(PushResult.Success); }
/// <summary> /// Pushes a message into the queue. /// </summary> internal async Task <PushResult> Push(QueueMessage message, MqClient sender) { if (!IsInitialized) { try { UpdateOptionsByMessage(message.Message); DeliveryHandlerBuilder handlerBuilder = new DeliveryHandlerBuilder { Server = Server, Queue = this, Headers = message.Message.Headers, DeliveryHandlerHeader = message.Message.FindHeader(HorseHeaders.DELIVERY_HANDLER) }; IMessageDeliveryHandler deliveryHandler = await Server.DeliveryHandlerFactory(handlerBuilder); InitializeQueue(deliveryHandler); handlerBuilder.TriggerAfterCompleted(); } catch (Exception e) { Server.SendError("INITIALIZE_IN_PUSH", e, $"QueueName:{Name}"); throw; } } if (Status == QueueStatus.Stopped) { return(PushResult.StatusNotSupported); } if (Options.MessageLimit > 0 && PriorityMessagesList.Count + MessagesList.Count >= Options.MessageLimit) { return(PushResult.LimitExceeded); } if (Options.MessageSizeLimit > 0 && message.Message.Length > Options.MessageSizeLimit) { return(PushResult.LimitExceeded); } //remove operational headers that are should not be sent to consumers or saved to disk message.Message.RemoveHeaders(HorseHeaders.DELAY_BETWEEN_MESSAGES, HorseHeaders.ACKNOWLEDGE, HorseHeaders.QUEUE_NAME, HorseHeaders.QUEUE_STATUS, HorseHeaders.QUEUE_TOPIC, HorseHeaders.PUT_BACK_DELAY, HorseHeaders.DELIVERY, HorseHeaders.DELIVERY_HANDLER, HorseHeaders.CC); //prepare properties message.Message.WaitResponse = Options.Acknowledge != QueueAckDecision.None; //if message doesn't have message id and "UseMessageId" option is enabled, create new message id for the message if (Options.UseMessageId && string.IsNullOrEmpty(message.Message.MessageId)) { message.Message.SetMessageId(Server.MessageIdGenerator.Create()); } //if we have an option maximum wait duration for message, set it after message joined to the queue. //time keeper will check this value and if message time is up, it will remove message from the queue. if (Options.MessageTimeout > TimeSpan.Zero) { message.Deadline = DateTime.UtcNow.Add(Options.MessageTimeout); } if (Options.HideClientNames) { message.Message.SetSource(null); } try { //fire message receive event Info.AddMessageReceive(); Decision decision = await DeliveryHandler.ReceivedFromProducer(this, message, sender); message.Decision = decision; bool allow = await ApplyDecision(decision, message); if (!allow) { return(PushResult.Success); } //trigger message produced event OnMessageProduced.Trigger(message); if (State.CanEnqueue(message)) { await RunInListSync(() => AddMessage(message)); if (State.TriggerSupported && !_triggering) { _ = Trigger(); } } else { _ = State.Push(message); } return(PushResult.Success); } catch (Exception ex) { Server.SendError("PUSH", ex, $"QueueName:{Name}"); Info.AddError(); try { Decision decision = await DeliveryHandler.ExceptionThrown(this, State.ProcessingMessage, ex); if (State.ProcessingMessage != null) { await ApplyDecision(decision, State.ProcessingMessage); if (!State.ProcessingMessage.IsInQueue) { if (decision.PutBack == PutBackDecision.Start) { AddMessage(State.ProcessingMessage, false); } else if (decision.PutBack == PutBackDecision.End) { AddMessage(State.ProcessingMessage); } } } } catch //if developer does wrong operation, we should not stop { } } return(PushResult.Success); }