Пример #1
1
        public void CanMeasureTimeSpentInSteps()
        {
            var stats = new PipelineStepProfilerStats();
            var pipeline = new DefaultPipeline()
                .OnReceive(new Step300())
                .OnReceive(new Step100())
                .OnReceive(new Step200());

            var profiler = new PipelineStepProfiler(pipeline, stats);

            var receivePipeline = profiler.ReceivePipeline();
            var invoker = new DefaultPipelineInvoker();
            var transportMessage = new TransportMessage(new Dictionary<string, string>(), new byte[0]);

            using (new DefaultTransactionContextScope())
            {
                var stepContext = new IncomingStepContext(transportMessage, AmbientTransactionContext.Current);

                invoker.Invoke(stepContext, receivePipeline).Wait();

                var stepStats = stats.GetStats();

                Console.WriteLine(string.Join(Environment.NewLine, stepStats));
            }
        }
Пример #2
0
        public void HandleMessage(TransportMessage transportMessage, ITransactionContext transactionContext)
        {
            var message = transportMessage.GetMessageLabel();

            var options = new List<KeyOption>();

            if (DefaultOutputQueue != null)
            {
                options.Add(KeyOption.New('d',
                    () => { MoveMessage(transportMessage, transactionContext, DefaultOutputQueue); },
                    "Move to default queue '{0}'", DefaultOutputQueue));
            }

            if (transportMessage.Headers.ContainsKey(Headers.SourceQueue))
            {
                var sourceQueue = transportMessage.Headers[Headers.SourceQueue];

                options.Add(KeyOption.New('s',
                    () => { MoveMessage(transportMessage, transactionContext, sourceQueue); },
                    "Return to source queue '{0}'", sourceQueue));
            }

            options.Add(KeyOption.New('c', () =>
            {
                Console.Write("queue > ");
                var queueName = Console.ReadLine();
                MoveMessage(transportMessage, transactionContext, queueName);
            }, "Enter custom queue name to move message to"));

            Prompt(message, options);

            Text.PrintLine();
        }
Пример #3
0
        /// <summary>
        /// Handles the poisonous message by forwarding it to the configured error queue
        /// </summary>
        public async Task HandlePoisonMessage(TransportMessage transportMessage, ITransactionContext transactionContext, string errorDescription)
        {
            var headers = transportMessage.Headers;

            string messageId ;

            if (!headers.TryGetValue(Headers.MessageId, out messageId))
            {
                messageId = "<unknown>";
            }

            headers[Headers.ErrorDetails] = errorDescription;
            headers[Headers.SourceQueue] = _transport.Address;

            var errorQueueAddress = _simpleRetryStrategySettings.ErrorQueueAddress;

            try
            {
                _log.Error("Moving message with ID {0} to error queue '{1}' - reason: {2}", messageId, errorQueueAddress, errorDescription);

                await _transport.Send(errorQueueAddress, transportMessage, transactionContext);
            }
            catch (Exception exception)
            {
                _log.Error(exception, "Could not move message with ID {0} to error queue '{1}' - will pause {2} to avoid thrashing",
                    messageId, errorQueueAddress, MoveToErrorQueueFailedPause);

                // if we can't move to error queue, we need to avoid thrashing over and over
                await Task.Delay(MoveToErrorQueueFailedPause);
            }
        }
        public async Task<Message> Deserialize(TransportMessage transportMessage)
        {
            string contentEncoding;

            if (!transportMessage.Headers.TryGetValue(Headers.ContentEncoding, out contentEncoding))
            {
                return await _serializer.Deserialize(transportMessage);
            }

            if (contentEncoding != GzipEncodingHeader)
            {
                var message = $"The message {transportMessage.GetMessageLabel()} has a '{Headers.ContentEncoding}' with the" +
                              $" value '{contentEncoding}', but this serializer decorator only knows how to decompress" +
                              $" '{GzipEncodingHeader}'";

                throw new ArgumentException(message);
            }

            var headers = transportMessage.Headers.Clone();
            var compressedBody = transportMessage.Body;

            headers.Remove(Headers.ContentEncoding);

            var uncompressedBody = _zipper.Unzip(compressedBody);
            var uncompressedTransportMessage = new TransportMessage(headers, uncompressedBody);

            return await _serializer.Deserialize(uncompressedTransportMessage);
        }
        /// <summary>
        /// Sends the given <see cref="TransportMessage"/> to the queue with the specified globally addressable name
        /// </summary>
        public async Task Send(string destinationAddress, TransportMessage message, ITransactionContext context)
        {
            context.OnCommitted(async () =>
            {
                var headers = message.Headers.Clone();
                var queue = GetQueue(destinationAddress);
                var messageId = Guid.NewGuid().ToString();
                var popReceipt = Guid.NewGuid().ToString();
                var timeToBeReceivedOrNull = GetTimeToBeReceivedOrNull(headers);
                var queueVisibilityDelayOrNull = GetQueueVisibilityDelayOrNull(headers);
                var cloudQueueMessage = Serialize(messageId, popReceipt, headers, message.Body);

                try
                {
                    var options = new QueueRequestOptions {RetryPolicy = new ExponentialRetry()};
                    var operationContext = new OperationContext();

                    await queue.AddMessageAsync(cloudQueueMessage, timeToBeReceivedOrNull, queueVisibilityDelayOrNull, options, operationContext);
                }
                catch (Exception exception)
                {
                    throw new RebusApplicationException(exception, $"Could not send message with ID {cloudQueueMessage.Id} to '{destinationAddress}'");
                }
            });
        }
Пример #6
0
 /// <summary>
 /// Constructs the step context, initially stashing the given <see cref="TransportMessage"/> and <see cref="ITransactionContext"/> into its bag of objects
 /// </summary>
 public IncomingStepContext(TransportMessage message, ITransactionContext transactionContext)
 {
     Save(message);
     Save(transactionContext);
     
     transactionContext.Items[StepContextKey] = this;
 }
Пример #7
0
        public void DispatchesDynamicMessageWhenDotNetTypeCannotBeFound()
        {
            var gotTheMessage = new ManualResetEvent(false);

            string messageText = null;

            _builtinHandlerActivator.Handle<dynamic>(async message =>
            {
                Console.WriteLine("Received dynamic message: {0}", message);

                messageText = message.something.text;

                gotTheMessage.Set();
            });

            var headers = new Dictionary<string, string>
            {
                {Headers.MessageId, Guid.NewGuid().ToString()},
                {Headers.ContentType, "application/json;charset=utf-8"},
            };

            var transportMessage = new TransportMessage(headers, Encoding.UTF8.GetBytes(@"{
    ""something"": {
        ""text"": ""OMG dynamic JSON BABY!!""
    }
}"));
            _network.Deliver(InputQueueName, new InMemTransportMessage(transportMessage));

            gotTheMessage.WaitOrDie(TimeSpan.FromSeconds(2));

            Assert.That(messageText, Is.EqualTo("OMG dynamic JSON BABY!!"));
        }
Пример #8
0
        public async Task Send(string destinationAddress, TransportMessage message, ITransactionContext context)
        {
            await _innerTransport.Send(destinationAddress, message, context);

            _sentMessages.Add(message);

            MessageSent(message);
        }
Пример #9
0
        protected string GetStringBody(TransportMessage transportMessage)
        {
            if (transportMessage == null)
            {
                throw new InvalidOperationException("Cannot get string body out of null message!");
            }

            return _defaultEncoding.GetString(transportMessage.Body);
        }
Пример #10
0
        public async Task Send(string destinationAddress, TransportMessage message, ITransactionContext context)
        {
            if (_sendLatencyMs.HasValue)
            {
                await Task.Delay(_sendLatencyMs.Value);
            }

            await _innerTransport.Send(destinationAddress, message, context);
        }
        public void WorksWithPrefetch(int prefetch, int numberOfMessages)
        {
            var activator = Using(new BuiltinHandlerActivator());
            var counter = new SharedCounter(numberOfMessages);

            activator.Handle<string>(async str =>
            {
                counter.Decrement();
            });

            Console.WriteLine("Sending {0} messages", numberOfMessages);

            var transport = GetTransport();
            var tasks = Enumerable.Range(0, numberOfMessages)
                .Select(i => string.Format("THIS IS MESSAGE # {0}", i))
                .Select(async msg =>
                {
                    using (var context = new DefaultTransactionContext())
                    {
                        var headers = DefaultHeaders();
                        var body = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(msg));
                        var transportMessage = new TransportMessage(headers, body);

                        await transport.Send(_queueName, transportMessage, context);

                        await context.Complete();
                    }
                })
                .ToArray();

            Task.WhenAll(tasks).Wait();

            Console.WriteLine("Receiving {0} messages", numberOfMessages);

            var stopwatch = Stopwatch.StartNew();

            Configure.With(activator)
                .Transport(t =>
                {
                    t.UseAzureServiceBus(StandardAzureServiceBusTransportFactory.ConnectionString, _queueName, _mode)
                        .EnablePrefetching(prefetch);
                })
                .Options(o =>
                {
                    o.SetNumberOfWorkers(5);
                    o.SetMaxParallelism(10);
                })
                .Start();

            counter.WaitForResetEvent(timeoutSeconds: (int)(numberOfMessages * 0.1 + 3));

            var elapsedSeconds = stopwatch.Elapsed.TotalSeconds;

            Console.WriteLine("Receiving {0} messages took {1:0.0} s - that's {2:0.0} msg/s",
                numberOfMessages, elapsedSeconds, numberOfMessages / elapsedSeconds);
        }
Пример #12
0
        async Task Send(IEnumerable<string> destinationAddressesList,
            TransportMessage transportMessage,
            ITransactionContext currentTransactionContext)
        {
            var sendTasks = destinationAddressesList
                .Select(address => _transport.Send(address, transportMessage, currentTransactionContext))
                .ToArray();

            await Task.WhenAll(sendTasks);
        }
        void MutateLegacyTransportMessage(IncomingStepContext context, Dictionary<string, string> headers, TransportMessage transportMessage)
        {
            var newHeaders = MapTrivialHeaders(headers);

            MapSpecialHeaders(newHeaders);

            newHeaders[LegacyMessageHeader] = "";

            context.Save(new TransportMessage(newHeaders, transportMessage.Body));
        }
Пример #14
0
        public async Task<Message> Deserialize(TransportMessage transportMessage)
        {
            using (var source = new MemoryStream(transportMessage.Body))
            {
                var headers = transportMessage.Headers.Clone();

                var body = _runtimeTypeModel.Deserialize(source, null, GetMessageType(transportMessage.Headers));

                return new Message(headers, body);
            }
        }
Пример #15
0
        public async Task Send(string destinationAddress, TransportMessage message, ITransactionContext context)
        {
            var outgoingMessages = context.GetOrAdd(OutgoingMessagesItemsKey, () =>
            {
                context.OnCommitted(async () => SendOutgoingMessages(context));

                return new ConcurrentQueue<OutgoingMessage>();
            });

            outgoingMessages.Enqueue(new OutgoingMessage(destinationAddress, message));
        }
Пример #16
0
        public void SetCommonHeaders(TransportMessage transportMessage)
        {
            var headers = transportMessage.Headers;

            if (_transport.Address != null)
            {
                headers[AuditHeaders.HandleQueue] = _transport.Address;
            }

            headers[AuditHeaders.AuditTime] = RebusTime.Now.ToString("O");
            headers[AuditHeaders.MachineName] = Environment.MachineName;
        }
Пример #17
0
        /// <summary>
        /// Delivers the given message to the queue identitied by the given <paramref name="destinationAddress"/>
        /// </summary>
        public async Task Send(string destinationAddress, TransportMessage message, ITransactionContext context)
        {
            if (destinationAddress == null) throw new ArgumentNullException("destinationAddress");
            if (message == null) throw new ArgumentNullException("message");
            if (context == null) throw new ArgumentNullException("context");

            if (!_network.HasQueue(destinationAddress))
            {
                throw new ArgumentException(string.Format("Destination queue address '{0}' does not exist!", destinationAddress));
            }

            context.OnCommitted(async () => _network.Deliver(destinationAddress, message.ToInMemTransportMessage()));
        }
Пример #18
0
        public async Task<Message> Deserialize(TransportMessage transportMessage)
        {
            var contentType = transportMessage.Headers.GetValue(Headers.ContentType);

            if (contentType != JsonUtf8ContentType)
            {
                throw new FormatException(string.Format("Unknown content type: '{0}' - must be '{1}' for the JSON serialier to work", contentType, JsonUtf8ContentType));
            }

            var bodyString = DefaultEncoding.GetString(transportMessage.Body);
            var bodyObject = JsonConvert.DeserializeObject(bodyString, _settings);
            var headers = transportMessage.Headers.Clone();
            return new Message(headers, bodyObject);
        }
Пример #19
0
        /// <summary>
        /// Deserializes the given transport message to a logical message using MsgPack. Throws if the
        /// required <see cref="Headers.ContentType"/> does not have the required <code>application/x-msgpack</code> value
        /// or of the .NET type of the message cannot be resolved from the <see cref="Headers.Type"/> header (which
        /// should carry the short assembly-qualified .NET type name of the message body)
        /// </summary>
        public async Task<Message> Deserialize(TransportMessage transportMessage)
        {
            var headers = transportMessage.Headers;
            var contentType = headers.GetValue(Headers.ContentType);

            if (contentType != MsgPackContentType)
            {
                throw new FormatException($"Unknown content type: '{contentType}' - must be '{MsgPackContentType}' for the MsgPack serialier to work");
            }

            var messageType = GetMessageType(headers);
            var body = _packer.Unpack(messageType, transportMessage.Body);

            return new Message(headers.Clone(), body);
        }
Пример #20
0
        /// <summary>
        /// Deserializes the given <see cref="TransportMessage"/> back into a <see cref="Message"/>. Expects a
        /// <see cref="Headers.ContentType"/> header with a value of <see cref="WireContentType"/>, otherwise
        /// it will not attempt to deserialize the message.
        /// </summary>
        public async Task<Message> Deserialize(TransportMessage transportMessage)
        {
            var contentType = transportMessage.Headers.GetValue(Headers.ContentType);

            if (contentType != WireContentType)
            {
                throw new FormatException($"Unknown content type: '{contentType}' - must be '{WireContentType}' for the JSON serialier to work");
            }

            using (var source = new MemoryStream(transportMessage.Body))
            {
                var body = _serializer.Deserialize(source);

                return new Message(transportMessage.Headers.Clone(), body);
            }
        }
Пример #21
0
        void PossiblyCompressTransportMessage(OutgoingStepContext context)
        {
            var transportMessage = context.Load<TransportMessage>();

            if (transportMessage.Body == null) return;

            if (transportMessage.Body.Length < _bodySizeThresholdBytes) return;

            var headers = transportMessage.Headers.Clone();
            var compressedBody = _zipper.Zip(transportMessage.Body);
            
            headers[Headers.ContentEncoding] = GzipEncodingHeader;

            var compressedTransportMessage = new TransportMessage(headers, compressedBody);

            context.Save(compressedTransportMessage);
        }
Пример #22
0
        /// <summary>
        /// Deserializes the given <see cref="TransportMessage"/> back into a <see cref="Message"/>
        /// </summary>
        public async Task<Message> Deserialize(TransportMessage transportMessage)
        {
            var contentType = transportMessage.Headers.GetValue(Headers.ContentType);

            if (contentType == JsonUtf8ContentType)
            {
                return GetMessage(transportMessage, _encoding);
            }

            if (contentType.StartsWith(JsonContentType))
            {
                var encoding = GetEncoding(contentType);
                return GetMessage(transportMessage, encoding);
            }

            throw new FormatException(string.Format("Unknown content type: '{0}' - must be '{1}' for the JSON serialier to work", contentType, JsonUtf8ContentType));
        }
Пример #23
0
        /// <summary>
        /// Deserializes the given <see cref="TransportMessage"/> back into a <see cref="Message"/>
        /// </summary>
        public async Task<Message> Deserialize(TransportMessage transportMessage)
        {
            var contentType = transportMessage.Headers.GetValue(Headers.ContentType);

            if (contentType != JsonUtf8ContentType)
            {
                throw new FormatException(string.Format("Unknown content type: '{0}' - must be '{1}' for the JSON serialier to work", contentType, JsonUtf8ContentType));
            }

            var headers = transportMessage.Headers.Clone();
            var messageType = GetMessageType(headers);
            var bodyString = Encoding.GetString(transportMessage.Body);
            var bodyObject = messageType != null 
                ? JSON.Deserialize(bodyString, messageType)
                : JSON.DeserializeDynamic(bodyString);
            return new Message(headers, bodyObject);
        }
Пример #24
0
        public async Task<TransportMessage> Serialize(Message message)
        {
            var transportMessage = await _serializer.Serialize(message);
            var body = transportMessage.Body;

            if (body.Length < _bodySizeThresholdBytes)
            {
                return transportMessage;
            }

            var headers = transportMessage.Headers.Clone();
            var compressedBody = _zipper.Zip(transportMessage.Body);

            headers[Headers.ContentEncoding] = GzipEncodingHeader;

            var compressedTransportMessage = new TransportMessage(headers, compressedBody);

            return compressedTransportMessage;
        }
Пример #25
0
        /// <summary>
        /// Sends the specified message to the logical queue specified by <paramref name="destinationQueueName"/> by writing
        /// a JSON serialied text to a file in the corresponding directory. The actual write operation is delayed until
        /// the commit phase of the queue transaction unless we're non-transactional, in which case it is written immediately.
        /// </summary>
        public async Task Send(string destinationQueueName, TransportMessage message, ITransactionContext context)
        {
            EnsureQueueInitialized(destinationQueueName);

            var destinationDirectory = GetDirectoryForQueueNamed(destinationQueueName);

            var serializedMessage = Serialize(message);
            var fileName = GetNextFileName();
            var fullPath = Path.Combine(destinationDirectory, fileName);

            context.OnCommitted(async () =>
            {
                using (var stream = File.OpenWrite(fullPath))
                using (var writer = new StreamWriter(stream, FavoriteEncoding))
                {
                    await writer.WriteAsync(serializedMessage);
                }
            });
        }
Пример #26
0
        public static BrokeredMessage CreateBrokeredMessage(TransportMessage message)
        {
            var headers = message.Headers.Clone();
            var brokeredMessage = new BrokeredMessage(new MemoryStream(message.Body), true);

            string timeToBeReceivedStr;
            if (headers.TryGetValue(Headers.TimeToBeReceived, out timeToBeReceivedStr))
            {
                timeToBeReceivedStr = headers[Headers.TimeToBeReceived];
                var timeToBeReceived = TimeSpan.Parse(timeToBeReceivedStr);
                brokeredMessage.TimeToLive = timeToBeReceived;
            }

            string deferUntilTime;
            if (headers.TryGetValue(Headers.DeferredUntil, out deferUntilTime))
            {
                var deferUntilDateTimeOffset = deferUntilTime.ToDateTimeOffset();
                brokeredMessage.ScheduledEnqueueTimeUtc = deferUntilDateTimeOffset.UtcDateTime;
                headers.Remove(Headers.DeferredUntil);
            }

            string contentType;
            if (headers.TryGetValue(Headers.ContentType, out contentType))
            {
                brokeredMessage.ContentType = contentType;
            }

            string correlationId;
            if (headers.TryGetValue(Headers.CorrelationId, out correlationId))
            {
                brokeredMessage.CorrelationId = correlationId;
            }

            brokeredMessage.Label = message.GetMessageLabel();

            foreach (var kvp in headers)
            {
                brokeredMessage.Properties[kvp.Key] = PossiblyLimitLength(kvp.Value);
            }

            return brokeredMessage;
        }
Пример #27
0
        public async Task StillWorksWhenIncomingMessageCannotBeDeserialized()
        {
            const string brokenJsonString = @"{'broken': 'json', // DIE!!1}";

            var headers = new Dictionary<string, string>
            {
                {Headers.MessageId, Guid.NewGuid().ToString()},
                {Headers.ContentType, "application/json;charset=utf-8"},
            };
            var body = Encoding.UTF8.GetBytes(brokenJsonString);
            var transportMessage = new TransportMessage(headers, body);
            var inMemTransportMessage = new InMemTransportMessage(transportMessage);  
            _network.Deliver(InputQueueName, inMemTransportMessage);

            await Task.Delay(1000);

            var failedMessage = _network.GetNextOrNull("error");

            Assert.That(failedMessage, Is.Not.Null);
            var bodyString = Encoding.UTF8.GetString(failedMessage.Body);
            Assert.That(bodyString, Is.EqualTo(brokenJsonString));
        }
Пример #28
0
        void MoveMessage(TransportMessage transportMessage, ITransactionContext transactionContext, string destinationQueue)
        {
            if (!_initializedQueues.Contains(destinationQueue))
            {
                _transport.CreateQueue(destinationQueue);
                _initializedQueues.Add(destinationQueue);
            }

            Text.Print("  => '{0}' - ", destinationQueue);

            try
            {
                _transport.Send(destinationQueue, transportMessage, transactionContext).Wait();

                Text.PrintLine("OK");
            }
            catch (Exception exception)
            {
                Text.PrintLine(exception.Message);
                throw;
            }
        }
Пример #29
0
        /// <summary>
        /// Sends the given <see cref="TransportMessage"/> to the queue with the specified globally addressable name
        /// </summary>
        public async Task Send(string destinationAddress, TransportMessage message, ITransactionContext context)
        {
            context.OnCommitted(async () =>
            {
                var queue = GetQueue(destinationAddress);
                var messageId = Guid.NewGuid().ToString();
                var popReceipt = Guid.NewGuid().ToString();
                var timeToBeReceived = GetTimeToBeReceivedOrNull(message);
                var cloudQueueMessage = Serialize(message, messageId, popReceipt);

                try
                {
                    var options = new QueueRequestOptions {RetryPolicy = new ExponentialRetry()};
                    var operationContext = new OperationContext();

                    await queue.AddMessageAsync(cloudQueueMessage, timeToBeReceived, null, options, operationContext);
                }
                catch (Exception exception)
                {
                    throw new RebusApplicationException(string.Format("Could not send message with ID {0} to '{1}'", cloudQueueMessage.Id, destinationAddress), exception);
                }
            });
        }
Пример #30
0
        /// <summary>
        /// Receives the next message by querying the messages table for a message with a recipient matching this transport's <see cref="Address"/>
        /// </summary>
        public async Task<TransportMessage> Receive(ITransactionContext context)
        {
            using (await _bottleneck.Enter())
            {
                var connection = await GetConnection(context);

                long? idOfMessageToDelete;
                TransportMessage receivedTransportMessage;

                using (var selectCommand = connection.CreateCommand())
                {
                    selectCommand.CommandText = string.Format(@"
	SET NOCOUNT ON

	;WITH TopCTE AS (
		SELECT	TOP 1
				[id],
				[headers],
				[body]
		FROM	{0} M WITH (ROWLOCK, READPAST)
		WHERE	M.[recipient] = @recipient
		AND		M.[visible] < getdate()
		AND		M.[expiration] > getdate()
		ORDER
		BY		[priority] ASC,
				[id] ASC
	)
	DELETE	FROM TopCTE
	OUTPUT	deleted.[id] as [id],
			deleted.[headers] as [headers],
			deleted.[body] as [body]
						
						", _tableName);

                    selectCommand.Parameters.Add("recipient", SqlDbType.NVarChar, RecipientColumnSize).Value = _inputQueueName;

                    using (var reader = await selectCommand.ExecuteReaderAsync())
                    {
                        if (!await reader.ReadAsync()) return null;

                        var headers = reader["headers"];
                        var headersDictionary = _headerSerializer.Deserialize((byte[])headers);

                        idOfMessageToDelete = (long)reader["id"];
                        var body = (byte[])reader["body"];

                        receivedTransportMessage = new TransportMessage(headersDictionary, body);
                    }
                }

                if (!idOfMessageToDelete.HasValue)
                {
                    return null;
                }


                return receivedTransportMessage;
            }
        }