private static void AfterDeliveryHandlerCreated(DeliveryHandlerBuilder builder) { IPersistentDeliveryHandler persistentHandler = builder.Queue.DeliveryHandler as IPersistentDeliveryHandler; if (persistentHandler == null) { return; } bool added = ConfigurationFactory.Manager.Add(builder.Queue, persistentHandler.DbFilename); if (added) { ConfigurationFactory.Manager.Save(); } }
/// <summary> /// Creates and initializes new persistent delivery handler for the queue /// </summary> /// <param name="builder">Delivery handler builder</param> /// <param name="deleteWhen">Decision when messages are deleted from disk</param> /// <param name="producerAckDecision">Decision when producer receives acknowledge</param> /// <param name="useRedelivery">True if want to keep redelivery data and send to consumers with message headers</param> /// <param name="key">Definition key for delivery handler. You can manage with that key, how the queue will be reloaded.</param> /// <param name="ackTimeoutPutback">Putback decision when ack message isn't received</param> /// <param name="nackPutback">Putback decision when negative ack is received</param> /// <returns></returns> public static async Task <IMessageDeliveryHandler> CreatePersistentDeliveryHandler(this DeliveryHandlerBuilder builder, DeleteWhen deleteWhen, ProducerAckDecision producerAckDecision, bool useRedelivery = false, PutBackDecision ackTimeoutPutback = PutBackDecision.End, PutBackDecision nackPutback = PutBackDecision.End, string key = "default") { DatabaseOptions databaseOptions = ConfigurationFactory.Builder.CreateOptions(builder.Queue); PersistentDeliveryHandler handler = new PersistentDeliveryHandler(builder.Queue, databaseOptions, deleteWhen, producerAckDecision, useRedelivery, key); handler.AckTimeoutPutBack = ackTimeoutPutback; handler.NegativeAckPutBack = nackPutback; await handler.Initialize(); builder.OnAfterCompleted(AfterDeliveryHandlerCreated); return(handler); }
/// <summary> /// Creates and initializes new persistent delivery handler for the queue /// </summary> /// <param name="builder">Delivery handler builder</param> /// <param name="factory">Creates new persistent delivery handler instance</param> /// <returns></returns> public static async Task <IMessageDeliveryHandler> CreatePersistentDeliveryHandler(this DeliveryHandlerBuilder builder, Func <DatabaseOptions, IPersistentDeliveryHandler> factory) { DatabaseOptions databaseOptions = ConfigurationFactory.Builder.CreateOptions(builder.Queue); IPersistentDeliveryHandler handler = factory(databaseOptions); await handler.Initialize(); builder.OnAfterCompleted(AfterDeliveryHandlerCreated); return(handler); }
/// <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); }