Last week I had a great OSB BlackBelt training of Samrat Ray and organized by the SOA Community In this training we talked a lot about Global Transactions ( XA), QoS ( Quality of Service ) in combination with Transports and JCA Adapters. Because this is so important ( you dont want to lose a Message ) I decide to make a blog about this subject and I will explain the different scenarios options you have in the Oracle Service Bus.
Before I can start I need to create and configure some Queues. In this blogpost I will use JMS for the Proxy and the Business service but you can also use EJB, MQ or the Direct Binding ( SOA Suite 11g ) for the Business Service, they all support XA, HTTP transport does not support XA ).
First create the RequestQ Queue combined with an ErrorQ Queue ( Now failed messages will be redirected to this Queue and won't be lost in Space), a ReponseQ Queue and a DestinationQ Queue ( used in the Business service )
Here is a picture how you can define an Error Queue on the RequestQ. Go to the Queue, select the Delivery Failure Tab in the Configuration Tab. Now you can set the Redirect Expiration Policy and select the Error destinations.
I start with a simple scenario. Add a message in the RequestQ and we will expect the message in the ResponseQ.
Add a Proxy Service ( any XML) and select JMS as protocol. OSB generates a default url with an internal XA connection factory and add the Queue name to this URL.
Add the destination Queue in the Proxy Service by enabling the Is Response Required option. Use text as Response Message Type ( else it will be hard to read the message ) and provide the Response URI.
Leave the Message Flow empty and a message in the RequestQ ( Go to the Queue, monitoring tab and a create a new message). Always change the Redelivery Limit ( Don't use the value -1 )
You will this message in the ResponseQ.
So far so good, now let's raise an Error on the Response Channel and take a look at the results. In the message flow I added a PipelinePair with a stage and an Error activity.
What you will see the message is removed from the RequestQ and the ResponseQ only gets a message with a SERVER_ERROR header and the content is gone.
We can solve this by making a change in the Proxy Service. Enable the Same Transaction For Response option, the response Thread will take over the transaction so when now something happens the transaction will be roll backed.
Add a message to the RequestQ, ( set the Redelivery to 2 else you will get a loop ) what you will see that the message now is added to the ErrorQ and not to the ResponseQ. This is good behaviour. Now you can re-process this message again by moving it to the RequestQ or let an ErrorHospital handle it.
The next step is adding a business service ( also use JMS and a XA Connection Factory ) and make this part of the Global Transaction. Add a routing to this Business Service in the message flow of the Proxy Service. This will also add the message to the DestinationQ. Make sure that the Message Type = text ( for this test only )
When you now put a message on the RequestQ, the message is also roll backed on the DestinationQ and only exists in the Error Queue.
When you disable the option Same Transaction for Response ( Default behavior ) then this message will be removed even when there is an error in the Response Channel of the Proxy Service.
The last part of this blog is taking a look at Quality of Service ( QoS ). QoS requires a transaction ( The Proxy Service need to start it ) and you can control, if the Business Service will take part on the Global Transaction. You need to add a Routing options activity to the request part of the Routing Node. First set QoS on Best Effort. Exactly Once is the default value when you use JMS and XA in the Proxy Service.
When you add a message on the RequestQ with a retry delivery of 5, You will see 6 messages in the DestinationQ. With Best Effort you will force the Business Service not to use the Global Transaction. Don't think you will like this,so let's change this to Exactly Once or remove this Routing Options action.
Conclusion: You need to think about your process and ask yourself is it a problem when your message is lost and what about when you deliver the same message again and again. Be aware one transaction for the request and response in the Proxy Service is not enabled by default and you need to configure it and test all the situations. Off course you need to use XA connection factories, Datasources and XA configured Resource Adapters.
HTTP Proxy or Business Services won't be part of XA. When you call a BPEL service you can use the Direct Binding transport for this.










Hello Biemond,
ReplyDeleteExcuse me for the spam...
I have a written a stateless session bean, which is compiled with out any errors, and is deployed on the weblogic server with out issues. But when Ii run my client program, i get this exceptions.
I need some input on the issue, I am faced with Severe deadlines:
Here is the full stack trace:
Caught an unexpected exception!
java.rmi.RemoteException: EJB Exception: ; nested exception is:
java.lang.NoClassDefFoundError: Could not initialize class sample.EJB.check.GenericServicesEJB_fd1cts_Impl
at weblogic.rjvm.ResponseImpl.unmarshalReturn(ResponseImpl.java:234)
at weblogic.rmi.cluster.ClusterableRemoteRef.invoke(ClusterableRemoteRef.java:348)
at weblogic.rmi.cluster.ClusterableRemoteRef.invoke(ClusterableRemoteRef.java:259)
at sample.EJB.check.GenericServicesEJB_fd1cts_EOImpl_1033_WLStub.getGrantsUpdatedOrgData(Unknown Source)
at sample.EJB.check.GenericServicesClient.main(GenericServicesClient.java:47)
Caused by: java.lang.NoClassDefFoundError: Could not initialize class sample.EJB.check.GenericServicesEJB_fd1cts_Impl
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at java.lang.Class.newInstance0(Class.java:355)
at java.lang.Class.newInstance(Class.java:308)
at weblogic.ejb.container.manager.BaseEJBManager.createNewBeanInstance(BaseEJBManager.java:222)
at weblogic.ejb.container.manager.BaseEJBManager.allocateBean(BaseEJBManager.java:231)
at weblogic.ejb.container.manager.StatelessManager.createBean(StatelessManager.java:303)
at weblogic.ejb.container.pool.StatelessSessionPool.createBean(StatelessSessionPool.java:201)
at weblogic.ejb.container.pool.StatelessSessionPool.getBean(StatelessSessionPool.java:127)
at weblogic.ejb.container.manager.StatelessManager.preInvoke(StatelessManager.java:148)
at weblogic.ejb.container.internal.BaseRemoteObject.preInvoke(BaseRemoteObject.java:230)
at weblogic.ejb.container.internal.StatelessRemoteObject.__WL_preInvoke(StatelessRemoteObject.java:41)
at sample.EJB.check.GenericServicesEJB_fd1cts_EOImpl.getGrantsUpdatedOrgData(GenericServicesEJB_fd1cts_EOImpl.java:1985)
at sample.EJB.check.GenericServicesEJB_fd1cts_EOImpl_WLSkel.invoke(Unknown Source)
at weblogic.rmi.internal.BasicServerRef.invoke(BasicServerRef.java:589)
at weblogic.rmi.cluster.ClusterableServerRef.invoke(ClusterableServerRef.java:230)
at weblogic.rmi.internal.BasicServerRef$1.run(BasicServerRef.java:477)
at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:363)
at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:147)
at weblogic.rmi.internal.BasicServerRef.handleRequest(BasicServerRef.java:473)
at weblogic.rmi.internal.wls.WLSExecuteRequest.run(WLSExecuteRequest.java:118)
at weblogic.work.ExecuteThread.execute(ExecuteThread.java:201)
at weblogic.work.ExecuteThread.run(ExecuteThread.java:173)
I do understand that a NoClassDefFoundError occurs, when a class is present in the classloader, but there was some problem loading the class. I am not able to figure out why I am getting an error on GenericServicesEJB_fd1cts_Impl which is present in the EJB ear file. I have started the whole project in new work spaces and installed on new servers as well, but nothing seemed to help in resolving the issue.
I have been struggling with this error for quite sometime now and wanted some external help in figuring out why the issue is happening and what can be done to trouble shoot the issue properly.
Any insights or advice will be greatly appreciated.
Regards,
Hi Biemond,
ReplyDeleteCan you tell me how to handle this scenario ?
1. OSB Proxy from AQ Topic
2. Message transformation and sending multiple messages to another AQ through business services
3. Now one of the messages failed to publish to the AQ business service
In this case, can we rollback all the previous messages sent to the AQ business service ?
Hi,
ReplyDeletethat is possible.
Do you use a split join / for each or something.
Important use xa jca adapters. In aq you should use a XA datasource and use transacted and set the QoS to exactly once and use same transaction for the response.
thanks