8 Replies Latest reply on Jan 8, 2009 8:16 AM by Mark Little

    ServiceInvoker / deliver in new transaction

    Bernd Ruecker Master

      Hi.

      I have an issue with the ServiceInvoker: When you want to use deliverSync in a transactional context (let's say in a EJB3-SLSB) and you use JMS as provider, this will not work correctly.

      Since the JMS message will be delivered in the transaction of the SLSB the ESB cannot start work before the transaction commits. But in deliverSync we wait for an answer (which cannot come).

      If I need a deliverSync within transactional context, my only possibility is to use deliverAsync in an own transaction and then wait for an answer, like this:

      try {
       // if we get an exception in the next method this transaction is rolled back as well
       callDeliverSyncInOwnTransaction();
       // now the ServiceInvoker succeeded, so the service is called correctly
       Message m = waitForAnswer();
       // do something with answer
      }
      catch (TimeoutException ex) {
       // OK, now we need some clever code to handle this situation!
       // message sent but the answer timed out and will come sometime in future
      }
      


      This behavior isn't really supported by the ServiceInvoker out of the box, or did I miss something? I would need to implement that callDeliverSyncInOwnTransaction myself (maybe I could use a SLSB method with @RequiresNew, or without using EJB I could suspend the transaction, create a new one, send and commit and resume the old one via the TransactionManager directly) and the waitForAnswer.

      Would be cool if the ESB supports this pattern out of the box, or what do you think?

      Since the deliverSync is quite powerfull, but more or less useless in JTA/JMS environment.

      Cheers
      Bernd

      P.S: Sorry if this is the wrong forum, wasn't sure about using User or Developer Forum, please move it accordingly if you think it is wrong...

        • 1. Re: ServiceInvoker / deliver in new transaction
          Mark Little Master

          Hi Bernd. We've had a few people (not many) ask about this in the past. Yes it could be supported, but the whole philosophy behind ESB is SOA which is about loose coupling. The synchronous request-response pattern that we are used to in other areas is not the default one that we would encourage. There are quite a few papers and articles on the Web about how and why one-way interactions are more appropriate. In that situation, a single global transaction does not work and something like JMS transacted sessions, or compensation transactions (e.g., WS-BA) is better. However, there are still some cases where a single transaction that encapsulates the sending of the request and all work done by that request (including possible any other onward calls the initial receiver may make) is needed. It's just not something that we support at the moment. But I'm sure it will come eventually (e.g., through the eventually support of WS-AT or JTS).

          • 2. Re: ServiceInvoker / deliver in new transaction
            Kevin Conner Master

            If you want to use deliverySync, and are not in a position to rearchitect the request using async messaging (see http://www.jboss.org/community/docs/DOC-9105 for an example), then the best solution is to execute the deliverSync within a method using @NotSupported.

            • 3. Re: ServiceInvoker / deliver in new transaction
              Bernd Ruecker Master

              Hi Mark.

              I agree 100% with you, synchronous delivery shouldn't be the default paradigm in a SOA world. And I think everybody starting with the ESB should read at least some of the literature you mentioned (I like especially Gregor Hohpes articles and interviews on that).

              But at some layer close to the client you often try to hide the asynchronism if possible (e.g. the UI should display some result if possible synchronously). In our app we face this requirement but since we do not expose the ServiceInvoker to the client, the client accesses a SLSB instead as entry point. And it will behave synchronously if we get an answer within the timeout period, otherwise the client will get a "try to fetch result later on"...

              I agree, that people should not be motivated to use synchronism in a SOA, but it would be nice to have it supported better out-of-the-box...

              Anyway, for the moment it seems I have to implement the code around the ServiceInvoker myself :-/. But at least I can post the code for other people facing this requirement later...

              • 4. Re: ServiceInvoker / deliver in new transaction
                Mark Little Master

                Hi Bernd. Couldn't you just use two correlated one-way requests instead of deliverSync?

                • 5. Re: ServiceInvoker / deliver in new transaction
                  Bernd Ruecker Master

                  Hi Mark.
                  You mean I have one SLSB with two methods:
                  - callService
                  - waitForAnswer
                  And the client has to call both in order?

                  Ideed, thats maybe not such a bad idea... I will think about it when I come back to it (currently I am stuck on other problems ;-))...

                  • 7. Re: ServiceInvoker / deliver in new transaction
                    Bernd Ruecker Master

                    Hi Mark,
                    I had a look into it again today. I have a problem of correlation now: After delivering asynchronously I have nothing, not even some ESB UUID. So how to wait for exactly this result message in a generic easy way?

                    The second problem: If I solve the correlation by some business identifier I still have to wait for the response of the service, but there is no way on the ServiceInvoker to do something like:

                    serviceInvoker.waitForResponse(categoryName, serviceName, timeout)
                    // or with correlation UUID
                    serviceInvoker.waitForResponse(categoryName, serviceName, uuid, timeout)
                    // or at least
                    serviceInvoker.getResponseCourier(categoryName, serviceName)
                    // or the like
                    


                    Otherwise I cannot do that in a generic way because I need to subscribe to JMS for example (but then I have to know the special queue name and I am bound to JMS).

                    What do you think? Or am I on the wrong path?
                    Cheers & Thanks
                    Bernd

                    • 8. Re: ServiceInvoker / deliver in new transaction
                      Mark Little Master

                      Hi Bernd. In this case you need an endpoint in the client that allows the service to call back to it when the work is done (the service then becomes a client and the client then becomes a service).

                      When the client does a send of the original work, I'd expect it to set the MessageID in the outgoing message. When the service sends back a response eventually, it sets the RelatesTo field in the response message and the client can use that to correlate the response with the original request.