/// <summary> /// Implements persistent message delivery handler /// </summary> /// <param name="builder">Horse MQ 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="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 HorseMqBuilder UsePersistentDeliveryHandler(this HorseMqBuilder builder, DeleteWhen deleteWhen, ProducerAckDecision producerAckDecision, bool useRedelivery = false, PutBackDecision ackTimeoutPutback = PutBackDecision.End, PutBackDecision nackPutback = PutBackDecision.End) { builder.Server.DeliveryHandlerFactory = async(dh) => { DatabaseOptions databaseOptions = ConfigurationFactory.Builder.CreateOptions(dh.Queue); PersistentDeliveryHandler handler = new PersistentDeliveryHandler(dh.Queue, databaseOptions, deleteWhen, producerAckDecision, useRedelivery, dh.DeliveryHandlerHeader); handler.AckTimeoutPutBack = ackTimeoutPutback; handler.NegativeAckPutBack = nackPutback; await handler.Initialize(); dh.OnAfterCompleted(AfterDeliveryHandlerCreated); return(handler); }; return(builder); }
/// <summary> /// Creates final decision from multiple decisions. /// Final decision has bests choices for each decision. /// </summary> internal static Decision CreateFinalDecision(Decision final, Decision decision) { bool allow = false; PutBackDecision putBack = PutBackDecision.No; bool save = false; DeliveryAcknowledgeDecision ack = DeliveryAcknowledgeDecision.None; if (decision.Allow) { allow = true; } if (decision.PutBack != PutBackDecision.No) { putBack = decision.PutBack; } if (decision.SaveMessage) { save = true; } if (decision.Acknowledge == DeliveryAcknowledgeDecision.Always) { ack = DeliveryAcknowledgeDecision.Always; } else if (decision.Acknowledge == DeliveryAcknowledgeDecision.IfSaved && final.Acknowledge == DeliveryAcknowledgeDecision.None) { ack = DeliveryAcknowledgeDecision.IfSaved; } return(new Decision(allow, save, putBack, ack)); }
/// <summary> /// Creates new decision with full parameters /// </summary> public Decision(bool allow, bool save, PutBackDecision putBack, DeliveryAcknowledgeDecision ack, QueueAcknowledgeDeliveryHandler acknowledgeDelivery) { Allow = allow; SaveMessage = save; PutBack = putBack; Acknowledge = ack; AcknowledgeDelivery = acknowledgeDelivery; }
/// <summary> /// Creates new decision with full parameters /// </summary> public Decision(bool allow, bool save, PutBackDecision putBack, DeliveryAcknowledgeDecision ack) { Allow = allow; SaveMessage = save; PutBack = putBack; Acknowledge = ack; AcknowledgeDelivery = null; }
/// <summary> /// Creates new decision without keeping messages and acknowledge /// </summary> public Decision(bool allow, bool save) { Allow = allow; SaveMessage = save; PutBack = PutBackDecision.No; Acknowledge = DeliveryAcknowledgeDecision.None; AcknowledgeDelivery = null; }
/// <inheritdoc /> public virtual async Task <Decision> AcknowledgeReceived(HorseQueue queue, HorseMessage acknowledgeMessage, MessageDelivery delivery, bool success) { if (success && DeleteWhen == DeleteWhen.AfterAcknowledgeReceived) { await DeleteMessage(delivery.Message.Message.MessageId); } DeliveryAcknowledgeDecision ack = DeliveryAcknowledgeDecision.None; if (ProducerAckDecision == ProducerAckDecision.AfterConsumerAckReceived) { ack = success ? DeliveryAcknowledgeDecision.Always : DeliveryAcknowledgeDecision.Negative; } PutBackDecision putBack = success ? PutBackDecision.No : NegativeAckPutBack; return(new Decision(true, false, putBack, ack)); }
/// <summary> /// Decision: Allow. /// If AcknowledgeWhen is AfterAcknowledge, acknowledge is sent to producer. /// </summary> public async Task <Decision> AcknowledgeReceived(HorseQueue queue, HorseMessage acknowledgeMessage, MessageDelivery delivery, bool success) { DeliveryAcknowledgeDecision ack = DeliveryAcknowledgeDecision.None; if (_producerAck == AcknowledgeWhen.AfterAcknowledge) { ack = success ? DeliveryAcknowledgeDecision.Always : DeliveryAcknowledgeDecision.Negative; } PutBackDecision putBack = PutBackDecision.No; if (!success) { putBack = _consumerAckFail; } return(await Task.FromResult(new Decision(true, false, putBack, ack))); }
/// <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> /// Quick IMessageDeliveryHandler implementation with acknowledge features. /// </summary> /// <param name="producerAck">Decision, when producer will receive acknowledge (or confirm)</param> /// <param name="consumerAckFail">Decision, what will be done if consumer sends nack or doesn't send ack in time</param> public AckDeliveryHandler(AcknowledgeWhen producerAck, PutBackDecision consumerAckFail) { _producerAck = producerAck; _consumerAckFail = consumerAckFail; }
/// <summary> /// Implements non-durable basic delivery handler with ack /// </summary> /// <param name="builder">Horse MQ Builder</param> /// <param name="producerAck">Decision, when producer will receive acknowledge (or confirm)</param> /// <param name="consumerAckFail">Decision, what will be done if consumer sends nack or doesn't send ack in time</param> public static HorseMqBuilder UseAckDeliveryHandler(this HorseMqBuilder builder, AcknowledgeWhen producerAck, PutBackDecision consumerAckFail) { builder.Server.DeliveryHandlerFactory = d => Task.FromResult <IMessageDeliveryHandler>(new AckDeliveryHandler(producerAck, consumerAckFail)); return(builder); }