public void CanSendAndReceiveMessageWithHeaders() { // arrange var encoding = Encoding.UTF7; var transportMessageToSend = new TransportMessageToSend { Body = encoding.GetBytes("this is some data"), Headers = new Dictionary <string, object> { { "key1", "value1" }, { "key2", "value2" }, } }; // act sender.Send(receiver.InputQueue, transportMessageToSend, new NoTransaction()); Thread.Sleep(MaximumExpectedQueueLatency); var receivedTransportMessage = receiver.ReceiveMessage(new NoTransaction()); // assert encoding.GetString(receivedTransportMessage.Body).ShouldBe("this is some data"); var headers = receivedTransportMessage.Headers; headers.ShouldNotBe(null); headers.Count.ShouldBe(2); headers.ShouldContainKeyAndValue("key1", "value1"); headers.ShouldContainKeyAndValue("key2", "value2"); 5.Times(() => receiver.ReceiveMessage(new NoTransaction()).ShouldBe(null)); }
public void CanReceiveAndDoMultipleSendsAtomically(bool commitTransactionAndExpectMessagesToBeThere) { sender.Send(receiver.InputQueueAddress, MessageWith("hello")); var destination1 = factory.CreateReceiver("destination1"); var destination2 = factory.CreateReceiver("destination2"); Thread.Sleep(300); // pretend that this is a message handler tx scope... using (var tx = new TransactionScope()) { // arrange var receivedTransportMessage = receiver.ReceiveMessage(); // act sender.Send(destination1.InputQueueAddress, receivedTransportMessage.ToForwardableMessage()); sender.Send(destination2.InputQueueAddress, receivedTransportMessage.ToForwardableMessage()); if (commitTransactionAndExpectMessagesToBeThere) { tx.Complete(); } } Thread.Sleep(300); // assert var msg1 = destination1.ReceiveMessage(); var msg2 = destination2.ReceiveMessage(); if (commitTransactionAndExpectMessagesToBeThere) { msg1.ShouldNotBe(null); Encoding.GetString(msg1.Body).ShouldBe("hello"); msg2.ShouldNotBe(null); Encoding.GetString(msg2.Body).ShouldBe("hello"); receiver.ReceiveMessage().ShouldBe(null); } else { msg1.ShouldBe(null); msg2.ShouldBe(null); receiver.ReceiveMessage().ShouldNotBe(null); } }
/// <inheritdoc /> public IReceivedMessageInternal ReceiveMessage(IMessageContext context) { //we can't attach the span since we don't have the parent until after we get a message //so save off the start and end times, and replace those in the child span below var start = DateTime.UtcNow; var message = _handler.ReceiveMessage(context); var end = DateTime.UtcNow; if (message == null) { return(null); } var activityContext = message.Extract(_tracer, _headers.StandardHeaders); //blocking operations can last forever for queues that can signal for new messages //so, we will treat this is a 0 ms operation, rather than have it possibly last for N if (IsBlockingOperation) { start = end; } using (var scope = _tracer.StartActivity("ReceiveMessage", ActivityKind.Internal, activityContext, startTime: start)) { scope?.AddMessageIdTag(message); scope?.SetTag("IsBlockingOperation", IsBlockingOperation); scope?.SetEndTime(end); return(message); } }
/// <summary> /// Receives a <see cref="ReceivedTransportMessage"/> using the underlying implementation of <see cref="IReceiveMessages"/> /// decrypting the message body if necessary, and remove the additional encryption headers /// </summary> public ReceivedTransportMessage ReceiveMessage(ITransactionContext context) { var receivedTransportMessage = innerReceiveMessages.ReceiveMessage(context); if (receivedTransportMessage == null) { return(null); } byte[] body; var headers = receivedTransportMessage.Headers.Clone(); if (headers.ContainsKey(Headers.Encrypted)) { var iv = receivedTransportMessage.GetStringHeader(Headers.EncryptionSalt); body = helper.Decrypt(receivedTransportMessage.Body, iv); headers.Remove(Headers.EncryptionSalt); headers.Remove(Headers.Encrypted); } else { body = receivedTransportMessage.Body; } return(new ReceivedTransportMessage { Id = receivedTransportMessage.Id, Headers = headers, Label = receivedTransportMessage.Label, Body = body, }); }
/// <summary> /// Tries the process the new incoming message. /// </summary> /// <param name="context">The context.</param> private void DoTry(IMessageContext context) { var transportMessage = _receiveMessages.ReceiveMessage(context); if (transportMessage == null) { //delay processing since we have no messages to process if (!_idle) { Idle(this, EventArgs.Empty); _idle = true; } _noMessageToProcessBackOffHelper.Value.Wait(); return; } //reset the back off counter - we have a message to process, so the wait times are now reset _noMessageToProcessBackOffHelper.Value.Reset(); if (_idle) { NotIdle(this, EventArgs.Empty); _idle = false; } _processMessage.Handle(context, transportMessage); }
void DoWork(IReceiveMessages messageQueue) { try { using (var tx = new TransactionScope()) { var ctx = new AmbientTransactionContext(); var receivedTransportMessage = messageQueue.ReceiveMessage(ctx); if (receivedTransportMessage == null) { return; } try { SendMessage(receivedTransportMessage); tx.Complete(); } catch (Exception e) { log.Error(e, "Could not send message {0} to destination URI {1} - waiting 1 sec before retrying", receivedTransportMessage.Id, destinationUri); Thread.Sleep(TimeSpan.FromSeconds(1)); } } } catch (Exception e) { log.Error("Unhandled exception during receive operation", e); } }
void DoWork(IReceiveMessages messageQueue) { try { using (var tx = new TransactionScope()) { var ctx = new AmbientTransactionContext(); var receivedTransportMessage = messageQueue.ReceiveMessage(ctx); if (receivedTransportMessage == null) return; try { SendMessage(receivedTransportMessage); tx.Complete(); } catch (Exception e) { log.Error(e, "Could not send message {0} to destination URI {1} - waiting 1 sec before retrying", receivedTransportMessage.Id, destinationUri); Thread.Sleep(TimeSpan.FromSeconds(1)); } } } catch (Exception e) { log.Error("Unhandled exception during receive operation", e); } }
void TryProcessIncomingMessage() { using (var transactionScope = BeginTransaction()) { var transportMessage = receiveMessages.ReceiveMessage(); if (transportMessage == null) { Thread.Sleep(20); return; } BeforeMessage(); var id = transportMessage.Id; var label = transportMessage.Label; if (errorTracker.MessageHasFailedMaximumNumberOfTimes(id)) { log.Error("Handling message {0} has failed the maximum number of times", id); MessageFailedMaxNumberOfTimes(transportMessage, errorTracker.GetErrorText(id)); errorTracker.StopTracking(id); PoisonMessage(); } else { try { var message = serializeMessages.Deserialize(transportMessage); var returnAddress = message.GetHeader(Headers.ReturnAddress); using (MessageContext.Enter(returnAddress)) { foreach (var logicalMessage in message.Messages) { var typeToDispatch = logicalMessage.GetType(); log.Debug("Dispatching message {0}: {1}", id, typeToDispatch); GetDispatchMethod(typeToDispatch).Invoke(this, new[] { logicalMessage }); } } } catch (Exception exception) { log.Debug("Handling message {0} ({1}) has failed", label, id); errorTracker.TrackDeliveryFail(id, exception); AfterMessage(exception); throw; } } transactionScope.Complete(); errorTracker.StopTracking(id); AfterMessage(null); } }
/// <summary> /// Receives a <see cref="ReceivedTransportMessage"/> using the underlying implementation of <see cref="IReceiveMessages"/> /// decrypting the message body if necessary, and remove the additional encryption headers /// </summary> public ReceivedTransportMessage ReceiveMessage(ITransactionContext context) { var message = innerReceiveMessages.ReceiveMessage(context); if (message == null) { return(null); } var clone = new ReceivedTransportMessage { Body = message.Body, Headers = message.Headers.Clone(), Label = message.Label, Id = message.Id }; var headers = clone.Headers; if (encryptionHelper != null) { if (headers.ContainsKey(Headers.Encrypted)) { var iv = clone.GetStringHeader(Headers.EncryptionSalt); clone.Body = encryptionHelper.Decrypt(clone.Body, iv); headers.Remove(Headers.EncryptionSalt); headers.Remove(Headers.Encrypted); } } if (compressionHelper != null) { if (headers.ContainsKey(Headers.Compression)) { var compressionType = (headers[Headers.Compression] ?? "").ToString(); switch (compressionType) { case Headers.CompressionTypes.GZip: clone.Body = compressionHelper.Decompress(clone.Body); break; default: throw new ArgumentException( string.Format( "Received message has the {0} header, but the compression type is set to {1} which cannot be handled", Headers.Compression, compressionType)); } headers.Remove(Headers.Compression); } } return(clone); }
/// <summary> /// Returns a message to process. /// </summary> /// <param name="context">The message context.</param> /// <returns> /// A message to process or null if there are no messages to process /// </returns> public IReceivedMessageInternal ReceiveMessage(IMessageContext context) { var result = _handler.ReceiveMessage(context); if (result != null) { ProcessResult(result); } return(result); }
/// <inheritdoc /> public IReceivedMessageInternal ReceiveMessage(IMessageContext context) { IReceivedMessageInternal result = null; if (_policy == null) { _policies.Registry.TryGet(_policies.Definition.ReceiveMessageFromTransport, out _policy); } if (_policy != null) { _policy.Execute(() => result = _handler.ReceiveMessage(context)); } else //no policy found { result = _handler.ReceiveMessage(context); } return(result); }
static IEnumerable<ReceivedTransportMessage> GetAllTheMessages(IReceiveMessages messageQueue, ITransactionContext transactionContext) { var messages = new List<ReceivedTransportMessage>(); ReceivedTransportMessage transportMessage; while ((transportMessage = messageQueue.ReceiveMessage(transactionContext)) != null) { messages.Add(transportMessage); } return messages; }
static IEnumerable <ReceivedTransportMessage> GetAllTheMessages(IReceiveMessages messageQueue, ITransactionContext transactionContext) { var messages = new List <ReceivedTransportMessage>(); ReceivedTransportMessage transportMessage; while ((transportMessage = messageQueue.ReceiveMessage(transactionContext)) != null) { messages.Add(transportMessage); } return(messages); }
public void CanReceiveAndDoOneSingleSendAtomically(bool commitTransactionAndExpectMessagesToBeThere) { sender.Send(receiver.InputQueueAddress, MessageWith("hello"), new NoTransaction()); var destination1 = factory.CreateReceiver("destination1"); Thread.Sleep(300.Milliseconds()); // pretend that this is a message handler tx scope... using (var tx = new TransactionScope()) { var ctx = new AmbientTransactionContext(); // arrange var receivedTransportMessage = receiver.ReceiveMessage(ctx); Assert.That(receivedTransportMessage, Is.Not.Null); // act sender.Send(destination1.InputQueueAddress, MessageWith("hello mr. 1"), ctx); if (commitTransactionAndExpectMessagesToBeThere) { tx.Complete(); } } Thread.Sleep(300.Milliseconds()); // assert var msg1 = destination1.ReceiveMessage(new NoTransaction()); if (commitTransactionAndExpectMessagesToBeThere) { Assert.That(msg1, Is.Not.Null); Assert.That(Encoding.GetString(msg1.Body), Is.EqualTo("hello mr. 1")); using (new TransactionScope()) { var ctx = new AmbientTransactionContext(); var receivedTransportMessage = receiver.ReceiveMessage(ctx); Assert.That(receivedTransportMessage, Is.Null); } } else { Assert.That(msg1, Is.Null); using (new TransactionScope()) { var ctx = new AmbientTransactionContext(); var receivedTransportMessage = receiver.ReceiveMessage(ctx); Assert.That(receivedTransportMessage, Is.Not.Null); Assert.That(Encoding.GetString(receivedTransportMessage.Body), Is.EqualTo("hello")); } } }
public ReceivedTransportMessage ReceiveMessage() { var receivedTransportMessage = innerReceiveMessages.ReceiveMessage(); var body = receivedTransportMessage.Headers.ContainsKey(Headers.Encrypted) ? Decrypt(receivedTransportMessage.Body) : receivedTransportMessage.Body; return(new ReceivedTransportMessage { Id = receivedTransportMessage.Id, Headers = receivedTransportMessage.Headers, Label = receivedTransportMessage.Label, Body = body, }); }
/// <inheritdoc /> public IReceivedMessageInternal ReceiveMessage(IMessageContext context) { //we can't attach the span since we don't have the parent until after we get a message //so save off the start and end times, and replace those in the child span below var start = DateTime.UtcNow; var message = _handler.ReceiveMessage(context); var end = DateTime.UtcNow; if (message == null) { return(null); } var spanContext = message.Extract(_tracer, _headers.StandardHeaders); //blocking operations can last forever for queues that can signal for new messages //so, we will treat this is a 0 ms operation, rather than have it possibly last for N if (IsBlockingOperation) { start = end; } if (spanContext != null) { using (IScope scope = _tracer.BuildSpan("ReceiveMessage").AddReference(References.FollowsFrom, spanContext).WithStartTimestamp(start) .StartActive(finishSpanOnDispose: true)) { scope.Span.AddMessageIdTag(message); scope.Span.SetTag("IsBlockingOperation", IsBlockingOperation); scope.Span.Finish(end); return(message); } } using (IScope scope = _tracer.BuildSpan("ReceiveMessage").WithStartTimestamp(start).StartActive(finishSpanOnDispose: true)) { scope.Span.AddMessageIdTag(message); scope.Span.SetTag("IsBlockingOperation", IsBlockingOperation); scope.Span.Finish(end); return(message); } }
void TryProcessIncomingMessage() { using (var transactionScope = BeginTransaction()) { var transportMessage = receiveMessages.ReceiveMessage(); if (transportMessage == null) { Thread.Sleep(20); return; } var id = transportMessage.Id; var label = transportMessage.Label; MessageContext context = null; if (errorTracker.MessageHasFailedMaximumNumberOfTimes(id)) { log.Error("Handling message {0} has failed the maximum number of times", id); MessageFailedMaxNumberOfTimes(transportMessage, errorTracker.GetErrorText(id)); errorTracker.StopTracking(id); try { PoisonMessage(transportMessage); } catch (Exception exceptionWhileRaisingEvent) { log.Error("An exception occurred while raising the PoisonMessage event: {0}", exceptionWhileRaisingEvent); } } else { try { BeforeTransportMessage(transportMessage); var message = serializeMessages.Deserialize(transportMessage); // successfully deserialized the transport message, let's enter a message context context = MessageContext.Enter(message.Headers); foreach (var logicalMessage in message.Messages) { context.SetLogicalMessage(logicalMessage); try { BeforeMessage(logicalMessage); var typeToDispatch = logicalMessage.GetType(); log.Debug("Dispatching message {0}: {1}", id, typeToDispatch); GetDispatchMethod(typeToDispatch).Invoke(this, new[] { logicalMessage }); AfterMessage(null, logicalMessage); } catch (Exception exception) { try { AfterMessage(exception, logicalMessage); } catch (Exception exceptionWhileRaisingEvent) { log.Error("An exception occurred while raising the AfterMessage event, and an exception occurred some time before that as well. The first exception was this: {0}. And then, when raising the AfterMessage event (including the details of the first error), this exception occurred: {1}", exception, exceptionWhileRaisingEvent); } throw; } finally { context.ClearLogicalMessage(); } } AfterTransportMessage(null, transportMessage); } catch (Exception exception) { log.Debug("Handling message {0} ({1}) has failed", label, id); try { AfterTransportMessage(exception, transportMessage); } catch (Exception exceptionWhileRaisingEvent) { log.Error("An exception occurred while raising the AfterTransportMessage event, and an exception occurred some time before that as well. The first exception was this: {0}. And then, when raising the AfterTransportMessage event (including the details of the first error), this exception occurred: {1}", exception, exceptionWhileRaisingEvent); } errorTracker.TrackDeliveryFail(id, exception); if (context != null) { context.Dispose(); //< dispose it if we entered } throw; } } transactionScope.Complete(); if (context != null) { context.Dispose(); //< dispose it if we entered } errorTracker.StopTracking(id); } }
void DoTry() { var transportMessage = receiveMessages.ReceiveMessage(TransactionContext.Current); if (transportMessage == null) { // to back off and relax then there's no messages to process, we do this successiveNullMessagesReceived++; var sleepTimeIndex = Math.Min(nullMessageSleepTimes.Length - 1, successiveNullMessagesReceived); var timeToSleep = nullMessageSleepTimes[sleepTimeIndex]; Thread.Sleep(timeToSleep); return; } successiveNullMessagesReceived = 0; var id = transportMessage.Id; var label = transportMessage.Label; MessageContext context = null; if (id == null) { HandlePoisonMessage(id, transportMessage); return; } if (errorTracker.MessageHasFailedMaximumNumberOfTimes(id)) { HandlePoisonMessage(id, transportMessage); errorTracker.StopTracking(id); return; } Exception transportMessageExceptionOrNull = null; try { BeforeTransportMessage(transportMessage); using (var scope = BeginTransaction()) { var message = serializeMessages.Deserialize(transportMessage); // successfully deserialized the transport message, let's enter a message context context = MessageContext.Establish(message.Headers); MessageContextEstablished(context); var unitsOfWork = unitOfWorkManagers.Select(u => u.Create()) .Where(u => !ReferenceEquals(null, u)) .ToArray(); //< remember to invoke the chain here :) try { foreach (var logicalMessage in message.Messages.Select(MutateIncoming)) { context.SetLogicalMessage(logicalMessage); Exception logicalMessageExceptionOrNull = null; try { BeforeMessage(logicalMessage); var typeToDispatch = logicalMessage.GetType(); log.Debug("Dispatching message {0}: {1}", id, typeToDispatch); GetDispatchMethod(typeToDispatch) .Invoke(this, new[] { logicalMessage }); } catch (Exception exception) { logicalMessageExceptionOrNull = exception; throw; } finally { try { AfterMessage(logicalMessageExceptionOrNull, logicalMessage); } catch (Exception exceptionWhileRaisingEvent) { if (logicalMessageExceptionOrNull != null) { log.Error( "An exception occurred while raising the AfterMessage event, and an exception occurred some" + " time before that as well. The first exception was this: {0}. And then, when raising the" + " AfterMessage event (including the details of the first error), this exception occurred: {1}", logicalMessageExceptionOrNull, exceptionWhileRaisingEvent); } else { log.Error("An exception occurred while raising the AfterMessage event: {0}", exceptionWhileRaisingEvent); } } context.ClearLogicalMessage(); } } foreach (var unitOfWork in unitsOfWork) { unitOfWork.Commit(); } } catch { foreach (var unitOfWork in unitsOfWork) { try { unitOfWork.Abort(); } catch (Exception abortException) { log.Warn("An error occurred while aborting the unit of work {0}: {1}", unitOfWork, abortException); } } throw; } finally { foreach (var unitOfWork in unitsOfWork) { unitOfWork.Dispose(); } } if (scope != null) { scope.Complete(); } } } catch (Exception exception) { transportMessageExceptionOrNull = exception; log.Debug("Handling message {0} ({1}) has failed", label, id); errorTracker.TrackDeliveryFail(id, exception); throw; } finally { try { AfterTransportMessage(transportMessageExceptionOrNull, transportMessage); } catch (Exception exceptionWhileRaisingEvent) { if (transportMessageExceptionOrNull != null) { log.Error( "An exception occurred while raising the AfterTransportMessage event, and an exception occurred some" + " time before that as well. The first exception was this: {0}. And then, when raising the" + " AfterTransportMessage event (including the details of the first error), this exception occurred: {1}", transportMessageExceptionOrNull, exceptionWhileRaisingEvent); } else { log.Error("An exception occurred while raising the AfterTransportMessage event: {0}", exceptionWhileRaisingEvent); } } if (context != null) { context.Dispose(); //< dispose it if we entered } } errorTracker.StopTracking(id); }
void DoTry() { var transportMessage = receiveMessages.ReceiveMessage(TransactionContext.Current); if (transportMessage == null) { // to back off and relax when there's no messages to process, we do this nullMessageReceivedBackoffHelper.Wait(); return; } nullMessageReceivedBackoffHelper.Reset(); var id = transportMessage.Id; var label = transportMessage.Label; MessageContext context = null; if (id == null) { HandlePoisonMessage(id, transportMessage); return; } if (errorTracker.MessageHasFailedMaximumNumberOfTimes(id)) { HandlePoisonMessage(id, transportMessage); errorTracker.StopTracking(id); return; } Exception transportMessageExceptionOrNull = null; try { BeforeTransportMessage(transportMessage); // Populate rebus-msg-id, if not set, from transport-level-id if (!transportMessage.Headers.ContainsKey(Headers.MessageId)) { transportMessage.Headers[Headers.MessageId] = transportMessage.Id; } using (var scope = BeginTransaction()) { var message = serializeMessages.Deserialize(transportMessage); // successfully deserialized the transport message, let's enter a message context context = MessageContext.Establish(message.Headers); MessageContextEstablished(context); var unitsOfWork = unitOfWorkManagers.Select(u => u.Create()) .Where(u => !ReferenceEquals(null, u)) .ToArray(); //< remember to invoke the chain here :) try { foreach (var logicalMessage in message.Messages.Select(MutateIncoming)) { context.SetLogicalMessage(logicalMessage); Exception logicalMessageExceptionOrNull = null; try { BeforeMessage(logicalMessage); var typeToDispatch = logicalMessage.GetType(); messageLogger.LogReceive(id, logicalMessage); try { var dispatchMethod = GetDispatchMethod(typeToDispatch); var parameters = new[] { logicalMessage }; dispatchMethod.Invoke(this, parameters); } catch (TargetInvocationException tie) { var exception = tie.InnerException; exception.PreserveStackTrace(); throw exception; } } catch (Exception exception) { logicalMessageExceptionOrNull = exception; throw; } finally { try { AfterMessage(logicalMessageExceptionOrNull, logicalMessage); } catch (Exception exceptionWhileRaisingEvent) { if (logicalMessageExceptionOrNull != null) { log.Error( "An exception occurred while raising the AfterMessage event, and an exception occurred some" + " time before that as well. The first exception was this: {0}. And then, when raising the" + " AfterMessage event (including the details of the first error), this exception occurred: {1}", logicalMessageExceptionOrNull, exceptionWhileRaisingEvent); } else { log.Error("An exception occurred while raising the AfterMessage event: {0}", exceptionWhileRaisingEvent); } } context.ClearLogicalMessage(); } } foreach (var unitOfWork in unitsOfWork) { try { unitOfWork.Commit(); } catch (Exception exception) { throw new UnitOfWorkCommitException(exception, unitOfWork); } } } catch { foreach (var unitOfWork in unitsOfWork) { try { unitOfWork.Abort(); } catch (Exception abortException) { log.Warn("An error occurred while aborting the unit of work {0}: {1}", unitOfWork, abortException); } } throw; } finally { foreach (var unitOfWork in unitsOfWork) { unitOfWork.Dispose(); } } if (scope != null) { scope.Complete(); } } } catch (Exception exception) { transportMessageExceptionOrNull = exception; log.Debug("Handling message {0} with ID {1} has failed", label, id); errorTracker.TrackDeliveryFail(id, exception); throw new MessageHandleException(id, exception); } finally { try { AfterTransportMessage(transportMessageExceptionOrNull, transportMessage); } catch (Exception exceptionWhileRaisingEvent) { if (transportMessageExceptionOrNull != null) { log.Error( "An exception occurred while raising the AfterTransportMessage event, and an exception occurred some" + " time before that as well. The first exception was this: {0}. And then, when raising the" + " AfterTransportMessage event (including the details of the first error), this exception occurred: {1}", transportMessageExceptionOrNull, exceptionWhileRaisingEvent); } else { log.Error("An exception occurred while raising the AfterTransportMessage event: {0}", exceptionWhileRaisingEvent); } } if (context != null) { context.Dispose(); //< dispose it if we entered } } errorTracker.StopTracking(id); }