void HandleMessageFailedMaxNumberOfTimes(ReceivedTransportMessage receivedTransportMessage, string errorDetail) { var transportMessageToSend = receivedTransportMessage.ToForwardableMessage(); log.Warn("Message {0} is forwarded to error queue", transportMessageToSend.Label); transportMessageToSend.Headers[Headers.SourceQueue] = receiveMessages.InputQueueAddress; transportMessageToSend.Headers[Headers.ErrorMessage] = errorDetail; transportMessageToSend.Headers[Headers.Bounced] = ""; try { using (var txc = ManagedTransactionContext.Get()) { sendMessages.Send(errorTracker.ErrorQueueAddress, transportMessageToSend, txc.Context); } } catch (Exception e) { log.Error(e, "An error occurred while attempting to move message with id {0} to the error queue '{1}'", receivedTransportMessage.Id, errorTracker.ErrorQueueAddress); // what to do? we need to throw again, or the message will not be rolled back and will thus be lost // - but we want to avoid thrashing, so we just log the badness and relax a little bit - that's // probably the best we can do Thread.Sleep(TimeSpan.FromSeconds(1)); throw; } }
/// <summary> /// Sends the message currently being handled to the specified endpoint, preserving all /// of the transport level headers. /// </summary> public void ForwardCurrentMessage(string destinationEndpoint) { using (var transactionContext = ManagedTransactionContext.Get()) { var messageContext = MessageContext.GetCurrent(); var currentMessage = messageContext.CurrentMessage; var headers = messageContext.Headers.Clone(); var message = new Message { Headers = headers, Messages = new[] { currentMessage } }; rebusBus.InternalSend(new List <string> { destinationEndpoint }, message, transactionContext.Context); } }
/// <summary> /// Core send method. This should be the only place where calls to the bus' /// <see cref="ISendMessages"/> instance gets called, except for when moving /// messages to the error queue. This method will bundle the specified batch /// of messages inside one single transport message, which it will send. /// </summary> internal void InternalSend(List <string> destinations, List <object> messages, bool published = false) { if (!started) { throw new InvalidOperationException( string.Format( @"Cannot send messages with a bus that has not been started! Or actually, you _could_ - but it would most likely be an error if you were using a bus without starting it... if you mean only to SEND messages, never RECEIVE anything, then you're not looking for an unstarted bus, you're looking for the ONE-WAY CLIENT MODE of the bus, which is what you get if you omit the inputQueue, errorQueue and workers attributes of the Rebus XML element and use e.g. .Transport(t => t.UseMsmqInOneWayClientMode())")); } using (var txc = ManagedTransactionContext.Get()) { foreach (var destination in destinations) { messages.ForEach(m => events.RaiseMessageSent(this, destination, m)); } var messageToSend = new Message { Messages = messages.Select(MutateOutgoing).ToArray(), }; var headers = MergeHeaders(messageToSend); // if a return address has not been explicitly set, set ourselves as the recipient of replies if we can if (!headers.ContainsKey(Headers.ReturnAddress)) { if (!configureAdditionalBehavior.OneWayClientMode) { headers[Headers.ReturnAddress] = GetInputQueueAddress(); } } if (MessageContext.HasCurrent) { var messageContext = MessageContext.GetCurrent(); // if we're currently handling a message with a correlation ID, make sure it flows... if (!headers.ContainsKey(Headers.CorrelationId)) { if (messageContext.Headers.ContainsKey(Headers.CorrelationId)) { headers[Headers.CorrelationId] = messageContext.Headers[Headers.CorrelationId].ToString(); } } // if we're currently handling a message with a user name, make sure it flows... if (!headers.ContainsKey(Headers.UserName)) { if (messageContext.Headers.ContainsKey(Headers.UserName)) { headers[Headers.UserName] = messageContext.Headers[Headers.UserName].ToString(); } } } // if, at this point, there's no correlation ID in a header, just provide one if (!headers.ContainsKey(Headers.CorrelationId)) { headers[Headers.CorrelationId] = Guid.NewGuid().ToString(); } // if, at this point, there's no rebus message ID in a header, just provide one if (!headers.ContainsKey(Headers.MessageId)) { headers[Headers.MessageId] = Guid.NewGuid().ToString(); } messageToSend.Headers = headers; InternalSend(destinations, messageToSend, txc.Context, published); } }