Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JmsOutboundGateway overwrites existing jms_correlationId [INT-3405] #7376

Closed
spring-operator opened this issue May 12, 2014 · 9 comments
Closed
Assignees
Milestone

Comments

@spring-operator
Copy link
Contributor

Manuel Polacek opened INT-3405 and commented

We have the requirement to use a consistent correlation id for a request through all our components. This works well until we try to use JmsOutboundGateway. With correlation-key set to "JMSCorrelationID" the gateway will create a new random correlation id instead of using the value of the existing header jms_correlationId (JmsHeaders.CORRELATION_ID).
Suggested fix: Check if header jms_correlationId exists and use it if set. If not set revert to the current behavior.


Affects: 3.0.2, 4.0 GA

Referenced from: pull request #1162

1 votes, 5 watchers

@spring-operator
Copy link
Contributor Author

Gary Russell commented

Given that the gateway is responsible for message correlation, it can't rely on the user-provided correlation id, for several reasons...

The framework cannot guarantee the id is unique.

Consider the flow o-b-gw->i-b-gw->...>o-b-gw->ib-gw->... where both inbound gateways use the same reply queue. If the correlation ids are the same the first gateway might get the response that is destined to the second.

So, the current behavior is for safety; we can consider adding a configuration option allowing the use of the existing correlation id if present, but it will be the application's responsibility to avoid the above problems.

In the meantime, perhaps you can copy your correlation Id to a different header and it will be transported as a JMS property.

@spring-operator
Copy link
Contributor Author

Manuel Polacek commented

Gary,
thank you for your fast response.
I understand the problem and the current behaviour for safety issues and i agree with you that this behaviour should not be changed.
An additional configuration option would give more flexibility to solve that problems. I thought about a configuration option like use-existing-correlation-id="(true|false)" which is set to false by default.

If you're interested in, i could prepare a pull request...

@spring-operator
Copy link
Contributor Author

Gary Russell commented

Thanks for your interest in contributing. Please be sure to "sign" the CLA as discussed in CONTRIBUTING.md.

We generally don't allow XML schema changes in point releases (e.g. 4.0.1), that's why I scheduled this for 4.1.

We can make the change to the gateway in 4.0.x, but the schema can't change, so the gateway would have to be wired up as a <bean/> (or @Bean ).

Alternatively, perhaps we can come up with a "special" value for correlation-key that tells the parser to set the new flag, e.g. correlation-key="JMSCorrelationID*", with the asterisk indicating use existing if present. I am not suggesting we support the asterisk on all values, just with JMSCorrelationID.

Perhaps Artem Bilan has another suggestion.

@spring-operator
Copy link
Contributor Author

Artem Bilan commented

For me JMSCorrelationID* looks like reasonable option.
Means "use an exisitng jmsRequest.getJMSCorrelationID() instead of generated one, if any"
And there is no reason to provide more options.
Of course there is need to correctly take care of its propagation and logic around null value.

Can be done for current release.

@spring-operator
Copy link
Contributor Author

Gary Russell commented

Merged

@spring-operator
Copy link
Contributor Author

Igor Petrov commented

Excuse me for by humble opinion, but shouldn't there be a way to leave correlation id untouched at all? In ongoing implementation if I utilize OutboundGateway with custom correlationId defined, there is still no way resulting jmsCorrelationId is not the same or null (JmsOutboundGateway#doSendAndReceiveWithGeneratedCorrelationId).

Imagine there is a code:

@MessagingGateway
public interface BookingGateway<T, R> {

    @Gateway(requestChannel = "bookingChannel")
    ListenableFuture<R> bookTicket(T ticket,
                                   @Header(IntegrationMessageHeaderAccessor.CORRELATION_ID) String correlationId,
                                   @Header(MessageHeaders.REPLY_CHANNEL) String replyTo);
}

@spring-operator
Copy link
Contributor Author

Gary Russell commented

I think you misunderstand; you need to set the JmsHeaders.CORRELATION_ID, not IntegrationMessageHeaderAccessor.CORRELATION_ID. It will be passed-through unchanged if the correlationKey is JMSCorrelationID* as long as you are not using a reply listener in the gateway.

Second, you should NOT be setting MessageHeaders.REPLY_CHANNEL header - that is an internal header used by the gateway to route the reply back to the BookingGateway after it has been returned the the JMS gateway.

If you are trying to set the JMSReplyTo destination, that has to be set on the JMS outbound gateway itself, not in the message (although it can be a destination expression that can be evaluated against the message).

@spring-operator
Copy link
Contributor Author

Igor Petrov commented

Thanks for reply, Gary. I got it, I just wrote my message out of context. In case above I utilize OutgoingGateway in order to gain request-reply behavior. There is a system that consists of three separate applications. First is a "producer", second can be called a "middle-tier" and finally "consumer" as a final destination (server).

  1. Producer send request through declared gateway.
  2. Middle has two IntegrationFlows (incoming and outgoing). It receives requests from producer, stores replyTo destination, wire-taps message to control bus (for metrics). Then substitutes replyTo for request message and resends it to server.
  3. Server takes request (actually not a server but a channel-adapter in integration patterns terminology. It communicates to the core via SOAP protocol within it's own IntegrationFlow). Then it replies to replyTo destination (substituted in the "middle").
  4. "Middle" takes reply back and searches for desired (in step Touched an inappropriate file #1) destination from repository.
  5. Then "middle" wire-taps message to control bus (for metrics again).
  6. "Middle" sends message (again, within one single IntegrationFlow) back to "producer".
  7. Finally, "producer" receives message and it have to match it with CorrelationID, but can not manage to it, because it had been overwritten on first step.

As you can see through 2nd to 6th steps - it's a Smart Proxy out there.
I believe that case above is exceptional in terms of spring-integration, but I also believe it is vital. // Sorry for late answer and my broken language once again.

@spring-operator
Copy link
Contributor Author

Gary Russell commented

but can not manage to it, because it had been overwritten on first step.

But we don't overwrite that header, JMS uses a different one. Something else must be dropping/changing the correlationId header.

I suggest you turn on DEBUG logging and follow the message flow.

There's no reason you shouldn't be able to get back the right correlation id.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants