Exemple #1
0
        static MessageWrapper BuildMessageWrapper(IOutgoingTransportOperation operation, TimeSpan?timeToBeReceived,
                                                  string destinationQueue)
        {
            var msg     = operation.Message;
            var headers = new Dictionary <string, string>(msg.Headers);

            var    messageIntent = default(MessageIntentEnum);
            string messageIntentString;

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

            return(new MessageWrapper
            {
                Id = msg.MessageId,
                Body = msg.Body,
                CorrelationId = headers.GetValueOrDefault(Headers.CorrelationId),
                Recoverable = operation.GetDeliveryConstraint <NonDurableDelivery>() == null,
                ReplyToAddress = headers.GetValueOrDefault(Headers.ReplyToAddress),
                TimeToBeReceived = timeToBeReceived ?? TimeSpan.MaxValue,
                Headers = headers,
                MessageIntent = messageIntent
            });
        }
Exemple #2
0
        MessageWrapper BuildMessageWrapper(IOutgoingTransportOperation operation, QueueAddress destinationQueue)
        {
            var msg     = operation.Message;
            var headers = new Dictionary <string, string>(msg.Headers);

            addressing.ApplyMappingOnOutgoingHeaders(headers, destinationQueue);

            var messageIntent = default(MessageIntentEnum);

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

            return(new MessageWrapper
            {
                Id = msg.MessageId,
                Body = msg.Body,
                CorrelationId = headers.GetValueOrDefault(Headers.CorrelationId),
                Recoverable = operation.GetDeliveryConstraint <NonDurableDelivery>() == null,
                ReplyToAddress = headers.GetValueOrDefault(Headers.ReplyToAddress),
                Headers = headers,
                MessageIntent = messageIntent
            });
        }
        static EventData ToEventData(IOutgoingTransportOperation operation, MessageMetadata meta = null)
        {
            var metadata         = meta ?? new MessageMetadata();
            var timeToBeReceived = operation.DeliveryConstraints.OfType <DiscardIfNotReceivedBefore>().FirstOrDefault();

            if (timeToBeReceived != null && timeToBeReceived.MaxTime != TimeSpan.Zero)
            {
                metadata.TimeToBeReceived = DateTime.UtcNow + timeToBeReceived.MaxTime;
            }
            metadata.MessageId = operation.Message.MessageId;
            metadata.Headers   = operation.Message.Headers;
            var type = operation.Message.Headers.ContainsKey(Headers.ControlMessageHeader)
                ? "ControlMessage"
                : operation.Message.Headers[Headers.EnclosedMessageTypes];

            byte[] data;
            string contentType;

            if (operation.Message.Headers.TryGetValue(Headers.ContentType, out contentType))
            {
                data = contentType != ContentTypes.Json
                    ? Encoding.UTF8.GetBytes(Convert.ToBase64String(operation.Message.Body))
                    : operation.Message.Body;
            }
            else
            {
                data           = new byte[0];
                metadata.Empty = true;
            }
            return(new EventData(Guid.NewGuid(), type, true, data, metadata.ToJsonBytes()));
        }
Exemple #4
0
        /// <summary>
        /// Gets the operation intent from the headers.
        /// </summary>
        /// <param name="operation">The operation.</param>
        /// <returns>The operation intent.</returns>
        public static MessageIntentEnum GetMessageIntent(this IOutgoingTransportOperation operation)
        {
            var messageIntent = default(MessageIntentEnum);

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

            return(messageIntent);
        }
Exemple #5
0
        MessageWrapper BuildMessageWrapper(IOutgoingTransportOperation operation, QueueAddress destinationQueue)
        {
            var msg = operation.Message;
            var headers = new Dictionary<string, string>(msg.Headers);

            addressing.ApplyMappingOnOutgoingHeaders(headers, destinationQueue);

            return new MessageWrapper
            {
                Id = msg.MessageId,
                Body = msg.Body,
                CorrelationId = headers.GetValueOrDefault(Headers.CorrelationId),
                // TODO: Will be addresses in another PR
                // Recoverable = operation.GetDeliveryConstraint<NonDurableDelivery>() == null,
                ReplyToAddress = headers.GetValueOrDefault(Headers.ReplyToAddress),
                Headers = headers,
                MessageIntent = operation.GetMessageIntent()
            };
        }
        static void ApplyCustomizationToOutgoingNativeMessage(IOutgoingTransportOperation transportOperation,
                                                              ServiceBusMessage message, TransportTransaction transportTransaction)
        {
            if (!transportOperation.Properties.TryGetValue(NativeMessageCustomizationBehavior.CustomizationKey,
                                                           out var key))
            {
                return;
            }

            var messageCustomizer = transportTransaction.Get <NativeMessageCustomizer>();

            if (!messageCustomizer.Customizations.TryGetValue(key, out var action))
            {
                Log.Warn(
                    $"Message {transportOperation.Message.MessageId} was configured with a native message customization but the customization was not found in {nameof(NativeMessageCustomizer)}");
                return;
            }

            action(message);
        }
Exemple #7
0
        static bool TryProcessDelayedRetry(IOutgoingTransportOperation operation, out UnicastTransportOperation operationToSchedule, out DateTimeOffset scheduleDate)
        {
            var messageHeaders = operation.Message.Headers;

            if (messageHeaders.TryGetValue(TimeoutManagerHeaders.Expire, out var expire))
            {
                var expiration = DateTimeExtensions.ToUtcDateTime(expire);

                var destination = messageHeaders[TimeoutManagerHeaders.RouteExpiredTimeoutTo];

                messageHeaders.Remove(TimeoutManagerHeaders.Expire);
                messageHeaders.Remove(TimeoutManagerHeaders.RouteExpiredTimeoutTo);

                operationToSchedule = new UnicastTransportOperation(operation.Message, destination, operation.RequiredDispatchConsistency, operation.DeliveryConstraints);

                scheduleDate = expiration;

                return(true);
            }

            operationToSchedule = null;
            scheduleDate        = default(DateTimeOffset);
            return(false);
        }
Exemple #8
0
 static bool TryGetConstraint <T>(IOutgoingTransportOperation operation, out T constraint) where T : DeliveryConstraint
 {
     constraint = operation.DeliveryConstraints.OfType <T>().FirstOrDefault();
     return(constraint != null);
 }
Exemple #9
0
        async Task WriteMessage(string destination, IOutgoingTransportOperation transportOperation, TransportTransaction transaction)
        {
            var message       = transportOperation.Message;
            var headerPayload = HeaderSerializer.Serialize(message.Headers);
            var headerSize    = Encoding.UTF8.GetByteCount(headerPayload);

            if (headerSize + message.Body.Length > maxMessageSizeKB * 1024)
            {
                throw new Exception($"The total size of the '{message.Headers[Headers.EnclosedMessageTypes]}' message body ({message.Body.Length} bytes) plus headers ({headerSize} bytes) is larger than {maxMessageSizeKB} KB and will not be supported on some production transports. Consider using the NServiceBus DataBus or the claim check pattern to avoid messages with a large payload. Use 'EndpointConfiguration.UseTransport<LearningTransport>().NoPayloadSizeRestriction()' to disable this check and proceed with the current message size.");
            }

            var nativeMessageId = Guid.NewGuid().ToString();
            var destinationPath = Path.Combine(basePath, destination);
            var bodyDir         = Path.Combine(destinationPath, LearningTransportMessagePump.BodyDirName);

            Directory.CreateDirectory(bodyDir);

            var bodyPath = Path.Combine(bodyDir, nativeMessageId) + LearningTransportMessagePump.BodyFileSuffix;

            await AsyncFile.WriteBytes(bodyPath, message.Body)
            .ConfigureAwait(false);

            DateTime?timeToDeliver = null;

            if (transportOperation.DeliveryConstraints.TryGet(out DoNotDeliverBefore doNotDeliverBefore))
            {
                timeToDeliver = doNotDeliverBefore.At;
            }
            else if (transportOperation.DeliveryConstraints.TryGet(out DelayDeliveryWith delayDeliveryWith))
            {
                timeToDeliver = DateTime.UtcNow + delayDeliveryWith.Delay;
            }

            if (timeToDeliver.HasValue)
            {
                if (transportOperation.DeliveryConstraints.TryGet(out DiscardIfNotReceivedBefore timeToBeReceived) && timeToBeReceived.MaxTime < TimeSpan.MaxValue)
                {
                    throw new Exception($"Postponed delivery of messages with TimeToBeReceived set is not supported. Remove the TimeToBeReceived attribute to postpone messages of type '{message.Headers[Headers.EnclosedMessageTypes]}'.");
                }

                // we need to "ceil" the seconds to guarantee that we delay with at least the requested value
                // since the folder name has only second resolution.
                if (timeToDeliver.Value.Millisecond > 0)
                {
                    timeToDeliver += TimeSpan.FromSeconds(1);
                }

                destinationPath = Path.Combine(destinationPath, LearningTransportMessagePump.DelayedDirName, timeToDeliver.Value.ToString("yyyyMMddHHmmss"));

                Directory.CreateDirectory(destinationPath);
            }

            var messagePath = Path.Combine(destinationPath, nativeMessageId) + ".metadata.txt";

            if (transportOperation.RequiredDispatchConsistency != DispatchConsistency.Isolated && transaction.TryGet(out ILearningTransportTransaction directoryBasedTransaction))
            {
                await directoryBasedTransaction.Enlist(messagePath, headerPayload)
                .ConfigureAwait(false);
            }
            else
            {
                // atomic avoids the file being locked when the receiver tries to process it
                await AsyncFile.WriteTextAtomic(messagePath, headerPayload)
                .ConfigureAwait(false);
            }
        }
Exemple #10
0
 public static T GetDeliveryConstraint <T>(this IOutgoingTransportOperation operation)
     where T : DeliveryConstraint
 {
     return(operation.DeliveryConstraints.OfType <T>().FirstOrDefault());
 }
        async Task <TMessage> PrepareMessage <TMessage>(IOutgoingTransportOperation transportOperation, HashSet <string> messageIdsOfMulticastedEvents)
            where TMessage : PreparedMessage, new()
        {
            var unicastTransportOperation = transportOperation as UnicastTransportOperation;

            // these conditions are carefully chosen to only execute the code if really necessary
            if (unicastTransportOperation != null &&
                messageIdsOfMulticastedEvents.Contains(unicastTransportOperation.Message.MessageId) &&
                unicastTransportOperation.Message.GetMessageIntent() == MessageIntentEnum.Publish &&
                unicastTransportOperation.Message.Headers.ContainsKey(Headers.EnclosedMessageTypes))
            {
                var mostConcreteEnclosedMessageType = unicastTransportOperation.Message.GetEnclosedMessageTypes()[0];
                var existingTopic = await topicCache.GetTopicArn(mostConcreteEnclosedMessageType).ConfigureAwait(false);

                if (existingTopic != null)
                {
                    var matchingSubscriptionArn = await snsClient.FindMatchingSubscription(queueCache, existingTopic, unicastTransportOperation.Destination)
                                                  .ConfigureAwait(false);

                    if (matchingSubscriptionArn != null)
                    {
                        return(null);
                    }
                }
            }

            var delayDeliveryWith  = transportOperation.DeliveryConstraints.OfType <DelayDeliveryWith>().SingleOrDefault();
            var doNotDeliverBefore = transportOperation.DeliveryConstraints.OfType <DoNotDeliverBefore>().SingleOrDefault();

            long delaySeconds = 0;

            if (delayDeliveryWith != null)
            {
                delaySeconds = Convert.ToInt64(Math.Ceiling(delayDeliveryWith.Delay.TotalSeconds));
            }
            else if (doNotDeliverBefore != null)
            {
                delaySeconds = Convert.ToInt64(Math.Ceiling((doNotDeliverBefore.At - DateTime.UtcNow).TotalSeconds));
            }

            if (!configuration.IsDelayedDeliveryEnabled && delaySeconds > TransportConfiguration.AwsMaximumQueueDelayTime)
            {
                throw new NotSupportedException($"To send messages with a delay time greater than '{TimeSpan.FromSeconds(TransportConfiguration.AwsMaximumQueueDelayTime)}', call '.UseTransport<SqsTransport>().UnrestrictedDurationDelayedDelivery()'.");
            }

            var sqsTransportMessage = new TransportMessage(transportOperation.Message, transportOperation.DeliveryConstraints);

            var serializedMessage = SimpleJson.SerializeObject(sqsTransportMessage, serializerStrategy);

            var messageId = transportOperation.Message.MessageId;

            var preparedMessage = new TMessage();

            await ApplyUnicastOperationMappingIfNecessary(unicastTransportOperation, preparedMessage as SqsPreparedMessage, delaySeconds, messageId).ConfigureAwait(false);
            await ApplyMulticastOperationMappingIfNecessary(transportOperation as MulticastTransportOperation, preparedMessage as SnsPreparedMessage).ConfigureAwait(false);

            preparedMessage.Body      = serializedMessage;
            preparedMessage.MessageId = messageId;
            preparedMessage.CalculateSize();
            if (preparedMessage.Size <= TransportConfiguration.MaximumMessageSize)
            {
                return(preparedMessage);
            }

            if (string.IsNullOrEmpty(configuration.S3BucketForLargeMessages))
            {
                throw new Exception("Cannot send large message because no S3 bucket was configured. Add an S3 bucket name to your configuration.");
            }

            var key = $"{configuration.S3KeyPrefix}/{messageId}";

            using (var bodyStream = new MemoryStream(transportOperation.Message.Body))
            {
                var putObjectRequest = new PutObjectRequest
                {
                    BucketName  = configuration.S3BucketForLargeMessages,
                    InputStream = bodyStream,
                    Key         = key
                };
                ApplyServerSideEncryptionConfiguration(putObjectRequest);

                await s3Client.PutObjectAsync(putObjectRequest).ConfigureAwait(false);
            }

            sqsTransportMessage.S3BodyKey = key;
            sqsTransportMessage.Body      = string.Empty;
            preparedMessage.Body          = SimpleJson.SerializeObject(sqsTransportMessage, serializerStrategy);
            preparedMessage.CalculateSize();

            return(preparedMessage);
        }