Skip to content

Support Capture of Original Inbound Message in ErrorMessage [INT-2116] #6100

Closed
@spring-operator

Description

@spring-operator

Gary Russell opened INT-2116 and commented

Currently, ErrorMessage.payload.failedMessage is the message that caused an exception to be thrown. In a complex flow, the error flow may have to have complex logic to deal with the Error message. Email thread follows...


Consider

JMS.mda->Jaxb.transformer->validate.sa->store.in.db.sa
    ->errorChannel->JMS.to.deadletterQ.oba

Let's say the service invoked by the validator <sa/> throws an exception.

The failed message in the ErrorMessage sent to the errorChannel is the one containing the jaxb object out of the transformer. If this object is not Serializable, KABOOM! We're in Loop City.

While I am sure many (most?) use cases would want to be able to access the actual message that caused the failure, in this case, we'd like to get the original message that came in to the inbound adapter.

We could, of course, put another JAXB transformer in the error flow to convert back to XML but, I am sure this could get very messy if the main flow has lots of transformations etc, in that the error flow would have to figure out where the failure occurred in order to do the appropriate transformation.

I can see a couple of ways out of this.

  1. Add an option to the inbound adapters/gateways to select which message we want in the E.M.
  2. Along with failedMessage, add originalMessage to the E.M.

Seems to me that #2 would be easiest, and most useful, perhaps.


Mark Fisher wrote:

Gary, how do you envision adding the original Message as well considering it's out of scope at the time the ErrorMessage is created? I can see two options:

  1. proactive - always record it (e.g. as a header) even though we don't always expect a downstream failure
  2. reactive - as we bubble back up through each catch block, if catching a MessagingException, we could add to it

With #2 we could actually keep track of all Message snapshots in the "flow" (which is really just a stack). The downside is that it might be excessive in terms of memory usage for "normal" cases - so somehow it would need to be configurable.

-Mark


I hadn't really thought it through, but was thinking of something like the following in MessagingGatewaySupport...

try {
    Message<?> originalMessage = this.messagingTemplate.convertAndSend(this.requestChannel, object, this.historyWritingPostProcessor);
}
catch (Exception e) {
    if (this.errorChannel != null) {
        this.messagingTemplate.send(this.errorChannel, new ErrorMessage(e, originalMessage));
    }
    else {
        this.rethrow(e, "failed to send message");
    }
}

(Change convertAndSend to return the original message).

This would be inexpensive, both in implementation and memory (convertAndSend already holds a reference to the original message until the send() returns anyway).

(MessageProducerSupport already has a reference to the original message).

The downside is it would only work for direct channels, but I am not sure we want the overhead of carrying the original message around in the headers.


Affects: 2.1 M1

Issue Links:

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions