Example #1
0
 /// <summary>
 /// Creates a new <see cref="UnicastTransportOperation" /> instance.
 /// </summary>
 public UnicastTransportOperation(OutgoingMessage message, string destination, DispatchProperties properties, DispatchConsistency requiredDispatchConsistency = DispatchConsistency.Default)
 {
     Message     = message;
     Destination = destination;
     Properties  = properties;
     RequiredDispatchConsistency = requiredDispatchConsistency;
 }
        protected Task SendMessage(
            string address,
            Dictionary <string, string> headers       = null,
            TransportTransaction transportTransaction = null,
            DispatchProperties dispatchProperties     = null,
            DispatchConsistency dispatchConsistency   = DispatchConsistency.Default,
            byte[] body = null)
        {
            var messageId = Guid.NewGuid().ToString();
            var message   = new OutgoingMessage(messageId, headers ?? new Dictionary <string, string>(), body ?? Array.Empty <byte>());

            if (message.Headers.ContainsKey(TestIdHeaderName) == false)
            {
                message.Headers.Add(TestIdHeaderName, testId);
            }

            if (transportTransaction == null)
            {
                transportTransaction = new TransportTransaction();
            }

            var transportOperation = new TransportOperation(message, new UnicastAddressTag(address), dispatchProperties, dispatchConsistency);

            return(transportInfrastructure.Dispatcher.Dispatch(new TransportOperations(transportOperation), transportTransaction));
        }
Example #3
0
        static bool CalculateDelay(DispatchProperties dispatchProperties, out long delay)
        {
            delay = 0;
            var delayed = false;

            if (dispatchProperties.DoNotDeliverBefore != null)
            {
                delayed = true;
                delay   = Convert.ToInt64(Math.Ceiling((dispatchProperties.DoNotDeliverBefore.At - DateTimeOffset.UtcNow).TotalSeconds));

                if (delay > DelayInfrastructure.MaxDelayInSeconds)
                {
                    throw new Exception($"Message cannot set to be delivered at '{dispatchProperties.DoNotDeliverBefore.At}' because the delay specified via {nameof(DelayedDeliveryOptionExtensions.DoNotDeliverBefore)} exceeds the maximum delay value '{TimeSpan.FromSeconds(DelayInfrastructure.MaxDelayInSeconds)}'.");
                }
            }
            else if (dispatchProperties.DelayDeliveryWith != null)
            {
                delayed = true;
                delay   = Convert.ToInt64(Math.Ceiling(dispatchProperties.DelayDeliveryWith.Delay.TotalSeconds));

                if (delay > DelayInfrastructure.MaxDelayInSeconds)
                {
                    throw new Exception($"Message cannot be delayed by '{dispatchProperties.DelayDeliveryWith.Delay}' because the delay specified via {nameof(DelayedDeliveryOptionExtensions.DelayDeliveryWith)} exceeds the maximum delay value '{TimeSpan.FromSeconds(DelayInfrastructure.MaxDelayInSeconds)}'.");
                }
            }

            return(delayed);
        }
        public override Task Invoke(IAuditContext context, Func <IRoutingContext, Task> stage)
        {
            var message = context.Message;

            if (context.Extensions.TryGet(out State state))
            {
                //transfer audit values to the headers of the message to audit
                foreach (var kvp in state.AuditValues)
                {
                    message.Headers[kvp.Key] = kvp.Value;
                }
            }

            var dispatchProperties = new DispatchProperties();

            if (timeToBeReceived.HasValue)
            {
                dispatchProperties.DiscardIfNotReceivedBefore = new DiscardIfNotReceivedBefore(timeToBeReceived.Value);
            }

            var dispatchContext = this.CreateRoutingContext(context.Message, new UnicastRoutingStrategy(context.AuditAddress), context);

            dispatchContext.Extensions.Set(dispatchProperties);

            return(stage(dispatchContext));
        }
Example #5
0
        public override Task Invoke(IRoutingContext context, Func <IDispatchContext, Task> stage)
        {
            var state = context.Extensions.GetOrCreate <State>();
            var dispatchConsistency = state.ImmediateDispatch ? DispatchConsistency.Isolated : DispatchConsistency.Default;

            var operations = new TransportOperation[context.RoutingStrategies.Count];
            var index      = 0;

            foreach (var strategy in context.RoutingStrategies)
            {
                var addressLabel = strategy.Apply(context.Message.Headers);
                var message      = new OutgoingMessage(context.Message.MessageId, context.Message.Headers, context.Message.Body);

                if (!context.Extensions.TryGet(out DispatchProperties dispatchProperties))
                {
                    dispatchProperties = new DispatchProperties();
                }

                operations[index] = new TransportOperation(message, addressLabel, dispatchProperties, dispatchConsistency);
                index++;
            }

            if (isDebugEnabled)
            {
                LogOutgoingOperations(operations);
            }

            if (!state.ImmediateDispatch && context.Extensions.TryGet(out PendingTransportOperations pendingOperations))
            {
                pendingOperations.AddRange(operations);
                return(Task.CompletedTask);
            }

            return(stage(this.CreateDispatchContext(operations, context)));
        }
        public async Task Should_Reschedule_Timeouts()
        {
            var expectedDeliveryAt = new DateTimeOffset(new DateTime(2020, 1, 1));

            var scenarioContext = new IntegrationScenarioContext();

            scenarioContext.RegisterTimeoutRescheduleRule <AMessage>((msg, currentDelay) =>
            {
                return(new DoNotDeliverBefore(expectedDeliveryAt));
            });

            var context = new TestableOutgoingSendContext
            {
                Message = new OutgoingLogicalMessage(typeof(AMessage), new AMessage())
            };

            context.Headers.Add(Headers.SagaId, "a-saga-id");
            context.Headers.Add(Headers.SagaType, "a-saga-type");
            context.Headers.Add(Headers.IsSagaTimeoutMessage, bool.TrueString);

            var properties = new DispatchProperties {
                DoNotDeliverBefore = new DoNotDeliverBefore(new DateTime(2030, 1, 1))
            };

            context.Extensions.Set(properties);

            var sut = new RescheduleTimeoutsBehavior(scenarioContext);;
            await sut.Invoke(context, () => Task.CompletedTask).ConfigureAwait(false);

            var rescheduledDoNotDeliverBefore = properties.DoNotDeliverBefore;

            Assert.AreEqual(expectedDeliveryAt, rescheduledDoNotDeliverBefore.At);
        }
Example #7
0
        internal static bool?ShouldUseDeadLetterQueue(this DispatchProperties dispatchProperties)
        {
            if (dispatchProperties.TryGetValue(KeyDeadLetterQueue, out var boolString))
            {
                return(bool.Parse(boolString));
            }

            return(null);
        }
        /// <summary>
        /// Creates a new instance of a <see cref="TransportOperation" />.
        /// </summary>
        public TransportOperation(string messageId, DispatchProperties properties, byte[] body, Dictionary <string, string> headers)
        {
            Guard.AgainstNullAndEmpty(nameof(messageId), messageId);

            MessageId = messageId;
            Options   = properties;
            Body      = body;
            Headers   = headers;
        }
        public static Message Convert(OutgoingMessage message, DispatchProperties dispatchProperties)
        {
            var result = new Message();

            if (message.Body != null)
            {
                result.BodyStream = new MemoryStream(message.Body);
            }


            AssignMsmqNativeCorrelationId(message, result);

            result.Recoverable = true;

            if (dispatchProperties.DiscardIfNotReceivedBefore?.MaxTime < MessageQueue.InfiniteTimeout)
            {
                result.TimeToBeReceived = dispatchProperties.DiscardIfNotReceivedBefore.MaxTime;
            }

            var addCorrIdHeader = !message.Headers.ContainsKey("CorrId");

            using (var stream = new MemoryStream())
            {
                var headers = message.Headers.Select(pair => new HeaderInfo
                {
                    Key   = pair.Key,
                    Value = pair.Value
                }).ToList();

                if (addCorrIdHeader)
                {
                    headers.Add(new HeaderInfo
                    {
                        Key   = "CorrId",
                        Value = result.CorrelationId
                    });
                }

                headerSerializer.Serialize(stream, headers);
                result.Extension = stream.ToArray();
            }

            var messageIntent = default(MessageIntentEnum);

            if (message.Headers.TryGetValue(Headers.MessageIntent, out var messageIntentString))
            {
                Enum.TryParse(messageIntentString, true, out messageIntent);
            }

            result.AppSpecific = (int)messageIntent;


            return(result);
        }
        public async Task Should_default_dlq_to_off_for_messages_with_ttbr()
        {
            var dispatchProperties = new DispatchProperties
            {
                DiscardIfNotReceivedBefore = new DiscardIfNotReceivedBefore(TimeSpan.FromMinutes(10))
            };

            var dispatchedMessage = await DispatchMessage("dlqOffForTTBR", dispatchProperties : dispatchProperties);

            Assert.False(dispatchedMessage.UseDeadLetterQueue);
        }
        public void Should_use_the_TTBR_in_the_send_options_if_set()
        {
            var properties = new DispatchProperties
            {
                DiscardIfNotReceivedBefore = new DiscardIfNotReceivedBefore(TimeSpan.FromDays(1))
            };


            var message = MsmqUtilities.Convert(new OutgoingMessage("message id", new Dictionary <string, string>(), new byte[0]), properties);

            Assert.AreEqual(TimeSpan.FromDays(1), message.TimeToBeReceived);
        }
        public async Task Should_allow_optin_for_dlq_on_ttbr_messages()
        {
            var transportSettings = new MsmqTransport {
                UseDeadLetterQueueForMessagesWithTimeToBeReceived = true
            };
            var dispatchProperties = new DispatchProperties
            {
                DiscardIfNotReceivedBefore = new DiscardIfNotReceivedBefore(TimeSpan.FromMinutes(10))
            };

            var dispatchedMessage = await DispatchMessage("dlqOnForTTBR", transportSettings, dispatchProperties);

            Assert.True(dispatchedMessage.UseDeadLetterQueue);
        }
        static void ApplyDeliveryConstraints(ServiceBusMessage message, DispatchProperties dispatchProperties)
        {
            if (dispatchProperties.DoNotDeliverBefore != null)
            {
                message.ScheduledEnqueueTime = dispatchProperties.DoNotDeliverBefore.At;
            }
            else if (dispatchProperties.DelayDeliveryWith != null)
            {
                // Delaying with TimeSpan is currently not supported, see https://github.com/Azure/azure-service-bus-dotnet/issues/160
                message.ScheduledEnqueueTime = DateTimeOffset.UtcNow + dispatchProperties.DelayDeliveryWith.Delay;
            }

            if (dispatchProperties.DiscardIfNotReceivedBefore != null)
            {
                message.TimeToLive = dispatchProperties.DiscardIfNotReceivedBefore.MaxTime;
            }
        }
Example #14
0
        static TimeSpan?GetDeliveryDelay(DispatchProperties properties)
        {
            var doNotDeliverBefore = properties.DoNotDeliverBefore;

            if (doNotDeliverBefore != null)
            {
                return(ToNullIfNegative(doNotDeliverBefore.At - DateTimeOffset.UtcNow));
            }

            var delay = properties.DelayDeliveryWith;

            if (delay != null)
            {
                return(ToNullIfNegative(delay.Delay));
            }

            return(null);
        }
Example #15
0
 async Task BreakConnectionBySendingInvalidMessage(CancellationToken cancellationToken)
 {
     try
     {
         var outgoingMessage = new OutgoingMessage("Foo", new Dictionary <string, string>(), new byte[0]);
         var props           = new DispatchProperties
         {
             DiscardIfNotReceivedBefore =
                 new DiscardIfNotReceivedBefore(TimeSpan.FromMilliseconds(-1))
         };
         var operation = new TransportOperation(outgoingMessage, new UnicastAddressTag(settings.EndpointName()), props);
         await sender.Dispatch(new TransportOperations(operation), new TransportTransaction(), cancellationToken);
     }
     catch (Exception ex) when(!ex.IsCausedBy(cancellationToken))
     {
         // Don't care
     }
 }
Example #16
0
        public async Task <int> Retry(IncomingMessage message, TimeSpan delay, TransportTransaction transportTransaction, CancellationToken cancellationToken = default)
        {
            var outgoingMessage = new OutgoingMessage(message.MessageId, new Dictionary <string, string>(message.Headers), message.Body);

            var currentDelayedRetriesAttempt = message.GetDelayedDeliveriesPerformed() + 1;

            outgoingMessage.SetCurrentDelayedDeliveries(currentDelayedRetriesAttempt);
            outgoingMessage.SetDelayedDeliveryTimestamp(DateTimeOffset.UtcNow);

            var dispatchProperties = new DispatchProperties
            {
                DelayDeliveryWith = new DelayDeliveryWith(delay)
            };
            var messageDestination = new UnicastAddressTag(endpointInputQueue);

            var transportOperations = new TransportOperations(new TransportOperation(outgoingMessage, messageDestination, dispatchProperties));

            await dispatcher.Dispatch(transportOperations, transportTransaction, cancellationToken).ConfigureAwait(false);

            return(currentDelayedRetriesAttempt);
        }
Example #17
0
        public async Task Should_honor_stored_delivery_constraints()
        {
            var messageId   = "id";
            var options     = new DispatchProperties();
            var deliverTime = DateTimeOffset.UtcNow.AddDays(1);
            var maxTime     = TimeSpan.FromDays(1);

            options["Destination"] = "test";

            options["DeliverAt"]        = DateTimeOffsetHelper.ToWireFormattedString(deliverTime);
            options["DelayDeliveryFor"] = TimeSpan.FromSeconds(10).ToString();
            options["TimeToBeReceived"] = maxTime.ToString();

            fakeOutbox.ExistingMessage = new OutboxMessage(messageId, new[]
            {
                new NServiceBus.Outbox.TransportOperation("x", options, new byte[0], new Dictionary <string, string>())
            });

            var context = CreateContext(fakeBatchPipeline, messageId);

            await Invoke(context);

            var operationProperties = new DispatchProperties(fakeBatchPipeline.TransportOperations.First().Properties);
            var delayDeliveryWith   = operationProperties.DelayDeliveryWith;

            Assert.NotNull(delayDeliveryWith);
            Assert.AreEqual(TimeSpan.FromSeconds(10), delayDeliveryWith.Delay);

            var doNotDeliverBefore = operationProperties.DoNotDeliverBefore;

            Assert.NotNull(doNotDeliverBefore);
            Assert.AreEqual(deliverTime.ToString(), doNotDeliverBefore.At.ToString());

            var discard = operationProperties.DiscardIfNotReceivedBefore;

            Assert.NotNull(discard);
            Assert.AreEqual(maxTime, discard.MaxTime);

            Assert.Null(fakeOutbox.StoredMessage);
        }
Example #18
0
        public void DispatchDelayedMessage(string id, byte[] extension, ReadOnlyMemory <byte> body, string destination, TransportTransaction transportTransaction)
        {
            var headersAndProperties = MsmqUtilities.DeserializeMessageHeaders(extension);
            var headers    = new Dictionary <string, string>();
            var properties = new DispatchProperties();

            foreach (var kvp in headersAndProperties)
            {
                if (kvp.Key.StartsWith(MsmqUtilities.PropertyHeaderPrefix))
                {
                    properties[kvp.Key] = kvp.Value;
                }
                else
                {
                    headers[kvp.Key] = kvp.Value;
                }
            }

            var request = new OutgoingMessage(id, headers, body);

            SendToDestination(transportTransaction, new UnicastTransportOperation(request, destination, properties));
        }
        Task Send(byte[] body, string messageType, TimeSpan timeToBeReceived, IMessageDispatcher dispatcher, CancellationToken cancellationToken)
        {
            var headers = new Dictionary <string, string>
            {
                [Headers.EnclosedMessageTypes] = messageType,
                [Headers.ContentType]          = ContentTypes.Json,
                [Headers.MessageIntent]        = sendIntent
            };

            if (localAddress != null)
            {
                headers[Headers.ReplyToAddress] = localAddress;
            }

            var outgoingMessage = new OutgoingMessage(Guid.NewGuid().ToString(), headers, body);
            var properties      = new DispatchProperties {
                DiscardIfNotReceivedBefore = new DiscardIfNotReceivedBefore(timeToBeReceived)
            };
            var operation = new TransportOperation(outgoingMessage, new UnicastAddressTag(destinationQueue), properties);

            return(dispatcher.Dispatch(new TransportOperations(operation), new TransportTransaction(), cancellationToken));
        }
            Task MessageReceivedOnChannel(MessageReceivedOnChannelArgs e, CancellationToken cancellationToken)
            {
                var body             = e.Body;
                var headers          = e.Headers;
                var id               = e.Id;
                var timeToBeReceived = e.TimeToBeReceived;

                var destination = endpointRouter.GetDestinationFor();

                Logger.Info("Sending message to " + destination);

                var outgoingMessage = new OutgoingMessage(id, headers, body);

                outgoingMessage.Headers[Headers.ReplyToAddress] = replyToAddress;

                var dispatchProperties = new DispatchProperties {
                    DiscardIfNotReceivedBefore = new DiscardIfNotReceivedBefore(timeToBeReceived)
                };

                var transportOperations = new TransportOperations(new TransportOperation(outgoingMessage, new UnicastAddressTag(destination), dispatchProperties, DispatchConsistency.Default));

                return(dispatchMessages.Dispatch(transportOperations, new TransportTransaction(), cancellationToken));
            }
Example #21
0
        public async Task Should_honor_stored_direct_routing()
        {
            var messageId  = "id";
            var properties = new DispatchProperties {
                ["Destination"] = "myEndpoint"
            };


            fakeOutbox.ExistingMessage = new OutboxMessage(messageId, new[]
            {
                new NServiceBus.Outbox.TransportOperation("x", properties, new byte[0], new Dictionary <string, string>())
            });

            var context = CreateContext(fakeBatchPipeline, messageId);

            await Invoke(context);

            var routing = fakeBatchPipeline.TransportOperations.First().AddressTag as UnicastAddressTag;

            Assert.NotNull(routing);
            Assert.AreEqual("myEndpoint", routing.Destination);
            Assert.Null(fakeOutbox.StoredMessage);
        }
Example #22
0
        public async Task Should_honor_stored_pubsub_routing()
        {
            var messageId  = "id";
            var properties = new DispatchProperties
            {
                ["EventType"] = typeof(MyEvent).AssemblyQualifiedName
            };


            fakeOutbox.ExistingMessage = new OutboxMessage(messageId, new[]
            {
                new NServiceBus.Outbox.TransportOperation("x", properties, new byte[0], new Dictionary <string, string>())
            });

            var context = CreateContext(fakeBatchPipeline, messageId);

            await Invoke(context);

            var routing = fakeBatchPipeline.TransportOperations.First().AddressTag as MulticastAddressTag;

            Assert.NotNull(routing);
            Assert.AreEqual(typeof(MyEvent), routing.MessageType);
            Assert.Null(fakeOutbox.StoredMessage);
        }
Example #23
0
        bool IsCombiningTimeToBeReceivedWithTransactions(TransportTransaction transaction,
                                                         DispatchConsistency requiredDispatchConsistency, DispatchProperties dispatchProperties)
        {
            if (!transportSettings.UseTransactionalQueues)
            {
                return(false);
            }

            if (requiredDispatchConsistency == DispatchConsistency.Isolated)
            {
                return(false);
            }

            var timeToBeReceivedRequested =
                dispatchProperties.DiscardIfNotReceivedBefore?.MaxTime < MessageQueue.InfiniteTimeout;

            if (!timeToBeReceivedRequested)
            {
                return(false);
            }

            if (Transaction.Current != null)
            {
                return(true);
            }


            return(TryGetNativeTransaction(transaction, out _));
        }
Example #24
0
 static void MergeDispatchProperties(ContextBag context, DispatchProperties dispatchProperties)
 {
     // we can't add the constraints directly to the SendOptions ContextBag as the options can be reused
     context.Set(new DispatchProperties(dispatchProperties));
 }
Example #25
0
        public static void Fill(this IBasicProperties properties, OutgoingMessage message, DispatchProperties dispatchProperties)
        {
            if (message.MessageId != null)
            {
                properties.MessageId = message.MessageId;
            }

            var messageHeaders = message.Headers ?? new Dictionary <string, string>();

            var delayed = CalculateDelay(dispatchProperties, out var delay);

            properties.Persistent = !messageHeaders.Remove(UseNonPersistentDeliveryHeader);

            properties.Headers = messageHeaders.ToDictionary(p => p.Key, p => (object)p.Value);

            if (delayed)
            {
                properties.Headers[DelayInfrastructure.DelayHeader] = Convert.ToInt32(delay);
            }

            if (dispatchProperties.DiscardIfNotReceivedBefore != null && dispatchProperties.DiscardIfNotReceivedBefore.MaxTime < TimeSpan.MaxValue)
            {
                // align with TimeoutManager behavior
                if (delayed)
                {
                    throw new Exception("Postponed delivery of messages with TimeToBeReceived set is not supported. Remove the TimeToBeReceived attribute to postpone messages of this type.");
                }

                properties.Expiration = dispatchProperties.DiscardIfNotReceivedBefore.MaxTime.TotalMilliseconds.ToString(CultureInfo.InvariantCulture);
            }

            if (messageHeaders.TryGetValue(NServiceBus.Headers.CorrelationId, out var correlationId) && correlationId != null)
            {
                properties.CorrelationId = correlationId;
            }

            if (messageHeaders.TryGetValue(NServiceBus.Headers.EnclosedMessageTypes, out var enclosedMessageTypes) && enclosedMessageTypes != null)
            {
                var index = enclosedMessageTypes.IndexOf(',');

                if (index > -1)
                {
                    properties.Type = enclosedMessageTypes.Substring(0, index);
                }
                else
                {
                    properties.Type = enclosedMessageTypes;
                }
            }

            if (messageHeaders.TryGetValue(NServiceBus.Headers.ContentType, out var contentType) && contentType != null)
            {
                properties.ContentType = contentType;
            }
            else
            {
                properties.ContentType = "application/octet-stream";
            }

            if (messageHeaders.TryGetValue(NServiceBus.Headers.ReplyToAddress, out var replyToAddress) && replyToAddress != null)
            {
                properties.ReplyTo = replyToAddress;
            }
        }
        public static ServiceBusMessage ToAzureServiceBusMessage(this OutgoingMessage outgoingMessage, DispatchProperties dispatchProperties, string incomingQueuePartitionKey)
        {
            var message = new ServiceBusMessage(outgoingMessage.Body)
            {
                // Cannot re-use MessageId to be compatible with ASB transport that could have native de-dup enabled
                MessageId = Guid.NewGuid().ToString()
            };

            // The value needs to be "application/octect-stream" and not "application/octet-stream" for interop with ASB transport
            message.ApplicationProperties[TransportMessageHeaders.TransportEncoding] = "application/octect-stream";

            message.TransactionPartitionKey = incomingQueuePartitionKey;

            ApplyDeliveryConstraints(message, dispatchProperties);

            ApplyCorrelationId(message, outgoingMessage.Headers);

            ApplyContentType(message, outgoingMessage.Headers);

            SetReplyToAddress(message, outgoingMessage.Headers);

            CopyHeaders(message, outgoingMessage.Headers);

            return(message);
        }
        static async Task <Message> DispatchMessage(string queueName, MsmqTransport settings = null, DispatchProperties dispatchProperties = null, CancellationToken cancellationToken = default)
        {
            if (settings == null)
            {
                settings = new MsmqTransport();
            }

            var path = $@".\private$\{queueName}";

            try
            {
                MsmqHelpers.DeleteQueue(path);
                MsmqHelpers.CreateQueue(path);

                var messageSender = new MsmqMessageDispatcher(settings, "timeouts");

                var bytes = new byte[]
                {
                    1
                };
                var headers         = new Dictionary <string, string>();
                var outgoingMessage = new OutgoingMessage("1", headers, bytes);

                dispatchProperties = dispatchProperties ?? new DispatchProperties();
                var transportOperation = new TransportOperation(outgoingMessage, new UnicastAddressTag(queueName), dispatchProperties);

                await messageSender.Dispatch(new TransportOperations(transportOperation), new TransportTransaction(), cancellationToken);

                using (var queue = new MessageQueue(path))
                    using (var message = queue.Receive(TimeSpan.FromSeconds(5)))
                    {
                        return(message);
                    }
            }
            finally
            {
                MsmqHelpers.DeleteQueue(path);
            }
        }