Announcement Announcement Module
No announcement yet.
Request/Reply with JmsOutboundGateway and Reply-Topics Page Title Module
Move Remove Collapse
Conversation Detail Module
  • Filter
  • Time
  • Show
Clear All
new posts

  • Request/Reply with JmsOutboundGateway and Reply-Topics


    if I understand the sendAndReceive()-Method in the JmsOutboundGateway (Spring Integration 2.0) correctly, it first sends the message to its destination. Then it constructs a message consumer on the reply destination to wait for the answer.

    I wonder if it would be possible to lost the reply message, in case (a) the reply-destination is a (non-temporarily) JMS Topic and (b) the reply comes (for whatever unlikely reason) so fast, that it arrives before the receive() on the message consumer is invoked.

    Is it (theoretically) possible that this situation happens? Or do I miss something?


  • #2
    Is there a specific reason for using a "Topic" as a response Destination? It seems like a Queue would be a better choice.


    • #3
      You're right, a Queue would be the better choice, but due to our Company's JMS policy we're forced to use Topics.


      • #4
        Okay. I just wanted to understand that first So, your question is valid. It seems that we would need to either create a durable subscriber or else have a separate thread for the consumer that starts prior to the producer sending the Message. Is that basically what you were suggesting?


        • #5
          Yep, exactly :-)

          For me a separate thread would be more comfortable than a Durable Subscriber: if the the server crashes before the reply is received, the reply would go into nirvana, which would be fine in that case IMHO. Having a Durable Subscriber (or a Queue), a Reply that will never be received (due to VM crash or similiar) would stay forever in the Queue/Durable Topic.

          Disadvantages: more complex to implement(?) and you cannot use the JMS Message/Correlation-Id as selection criteria for the reply, as the Id is not known at the time you start to listening...


          • #6
            Yes, it's that correlationId part that's tricky...


            • #7
              As always, I'm sure you find a solution :-)

              Maybe it would be possible to use an extra JMS header with a self-generated id (UUID eg). Problem would be that the receiver is forced to include that header/the id in it's reply.


              • #8
                I did just want to mention that this should not be a problem at all when relying on temporary destinations. In fact, both QueueRequestor and TopicRequestor implementations (the vanilla JMS equivalent of our outbound gateway) do use TemporaryQueue and TemporaryTopic instances, respectively.

                The only reason we do not simply rely upon those *Requestors is that we want to provide the *option* of using an explicit, potentially shared Destination along with the correlationID.

                My next question, therefore, is if it would be sufficient to rely on a temporary Destination? If so, does even the creation of a temporary instance used only as a replyTo header need to conform to the Topic-only policy?


                • #9
                  I'm not sure, but I will check. Thank you very much so far.

                  BTW: maybe it would be helpful to add a hint in the documentation that messages can get lost when using Topics (as the API of JmsOutboundGateway supports that kind of destination)?


                  • #10
                    Out of curiosity, have you in fact witnessed lost Messages following that approach?


                    • #11
                      Nope, as of today we are not using Spring Integration in production but evaluate it to see if we can replace our home-grown solutions with it.

                      Personally I don't expected any lost message here, but you know... Murphy's law... :-)


                      • #12
                        Okay. It is clear that the race condition does exist. So, I'm going to try to reproduce it, but realizing that the race is indeed *possible*, my current thinking is that the best way to handle this is to create our own CorrelationID value as you had mentioned. We then just need to create the MessageConsumer instance prior to sending the Message.


                        • #13
                          Here's a quick update on the current plan for this issue:

                          I was able to simulate the race condition (even with a 0-latency echo responder, the timeout occurs rather infrequently while awaiting the reply Message, but it does occur).

                          The default behavior will remain the same. That means we will send a Message without any extra headers, and register a Consumer that uses the CorrelationID='..' selector, expecting that value to be the same as the generated ID of the Message that has been sent. That should be fine as long as there is either no explicit "replyDestination" set (in which case a TemporaryQueue is used) or the explicit reply Destination is itself a Queue instance. In other words, the only time this default behavior is not recommended is when the explicitly provided reply Destination is a Topic.

                          If the explicit reply Destination *is* a Topic, and the default behavior is in place, we will likely log a warning message that indicates the timeout could occur.

                          We will add support for a "correlationKey" String property on the outbound gateway (and via namespace support on the outbound-gateway element). If that String is provided, then *instead of* the default behavior, we will provide a JMS property with that "correlationKey" as its name and a UUID value that we generate internally (not planning to expose that generation strategy at this point). The Consumer will then use that correlationKey's value in its MessageSelector. The key point is that the value is available *prior to* sending the request Message, and therefore the Consumer can be created (along with its MessageSelector) before the request Message is sent. That means the window of vulnerability is closed, and the timeout will not occur.

                          We will also add support for the "correlationKey" String property on the inbound gateway (and via namespace support on the inbound-gateway element). If provided, then the value of that property will be taken from the request Message and will be copied as-is with the same property name into the reply Message. Therefore that value will be available for the Consumer that is waiting for the response. Therefore, if someone is using Spring Integration on both sides of a JMS request/reply exchange, the custom correlationKey can be used to ensure symmetry as long as the same value is provided for both.

                          One last thing that we might consider... if we detect "JMSCorrelationID" as the "correlationKey" property's value, then we can use the actual JMSCorrelationID, but generally we would recommend either sticking with the default (where the request MessageID is expected to be in the reply Message's CorrelationID) or using a custom property name to store the same value on both the request and the reply Message.

                          Does that make sense? Any concerns?


                          • #14
                            This has been implemented as described in my previous post (immediately above this). These are the relevant commits:

                            Please test it out with a local build (or the next nightly) and let us know how it goes.



                            • #15
                              Hi Mark,

                              thanks for the update. I will try the changes in the next days.