Thursday, February 10, 2011

handleTopLevelFault - SOA 10.1.3.5

I think all of us know that transaction=participate in 10.1.3.3 was replaced by handleTopLevelFault=true in 10.1.3.5. I never realized the impact it had in our processes and how Oracle keep changing their mind on what this value is and how the server behaves.

First of all, in 10.1.3.3, all BPEL processes DON'T participate in transaction by default. Which means if you have, process A -> Process B -> Process C, and

[C] is disabled

try {
    insert table 1
    invoke C
} catch {
    insert table 2
    throw
}


In this case, upon the failure of invoke C, entry in table 1 or 2 will never roll back, even if data sources are configured for XA transaction. If you do put transaction=partipate in your process at configuration level, then this process and their operation would be in Global transaction and throw activity would roll back insert in table 1 and 2.

[Note if you don't have throw, it would act like there is no error and nothing would ever roll back in any scenario, which is quite expected.]

Now, in 10.1.3.4, they replaced transaction=participate with handleTopLevelFault=false. The default value in the code [com.collaxa.cube.engine.core.map.BPELProcessBlock] was true. That's why behavior would be exactly same as 10.1.3.3. Nothing would participate in transaction unless you explicitly specify it to be. You can not define this property at domain level, it is only supported at process level.

In 10.1.3.5, the default value in [com.collaxa.cube.engine.core.map.BPELProcessBlock] got changed to "false". It caused numerous problems to us. Based on AIA best practice, we always have our own try/catch block, we do some processing in catch block (e.g. update db, queue, etc) and then we rethrow the error so the caller can get details of the error and instance can show as faulted. We had the pattern mentioned earlier all over the places. In 10.1.3.3 we could see the data which were inserted from catch block, but in 10.1.3.5 everything just rolled back because it started participating in transaction by default.

I agree, not a very good coding practice but it worked in 10.1.3.3 and nobody realized it can cause transaction issues during upgrade. The ideal solution should be to be catch block in local transaction so during roll back it doesn't rollback your work in catch activity.

[C] is disabled
try {
    insert table A
    invoke C
} catch {
    insert table B [make sure DB adapter is using tx-level='local' in data source]
    throw
}


Anyways, we had more than 200+ processes and we couldn't afford changing the code for each one of them, so I came up with neat solution which worked out without any issues. I wrote BPELClient API to insert "handleTopLevelFault=true" in majority of the BPEL processes, and that's it. No restart and no code change and life was back to normal. The only flow would be that if somebody redeploys the code and overwrites descriptor, but we can just run the util again in that case.

Here is the how code looked like:
ProcessDescriptor processDescriptor = bpelProcessHandle.getDescriptor();
ConfigurationsDescriptor configurationsDescriptor = processDescriptor.getConfigurations();
configurationsDescriptor.setPropertyValue("handleTopLevelFault",appropriateValue);  // set or add
bpelProcessHandle.updateDescriptor(processDescriptor);




Another side effect of handleTopLevelFault



If your process has handleTopLevelFault = true, it will show the Faulted Instance in Flow view and Audit view in BPELConsole

if your process has handleTopLevelFault = false (or don't have this property in 10.1.3.5), it will not show the instance in flow view and will only show in Audit view. That was some new enhancement added in 10.1.3.5.

I fixed the JavaScript issue so it shows up the faulted instance in Flow view even if you have handleTopLevelFault=false. Details can be found at http://chintanblog.blogspot.com/2011/01/bpelconsole-faulted-instance-in-10135.html

5 comments:

Wish said...

Hi ,
I want to update the configuration of the bpel process dynamically using the bpel api. (Oracle BPEL 10.1.3.3)

Here is my code.

====================================
Locator locator = new Locator("default", "test", _properties );
com.oracle.bpel.client.IBPELProcessHandle handle = locator.lookupProcess("TestProcess");

ProcessDescriptor processDescriptor = handle.getDescriptor();

ConfigurationsDescriptor configurationsDescriptor = processDescriptor.getConfigurations();

configurationsDescriptor.setPropertyValue("transaction","false"); // set or add
handle.updateDescriptor(processDescriptor);
===========================================================

But I am getting the following exception:

11/04/07 17:57:44 java.lang.NullPointerException
11/04/07 17:57:44 at testchangedescriptors.TestDescription.Test(TestDescription.java:55)
11/04/07 17:57:44 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
11/04/07 17:57:44 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
11/04/07 17:57:44 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
11/04/07 17:57:44 at java.lang.reflect.Method.invoke(Method.java:592)
11/04/07 17:57:44 at oracle.j2ee.ws.server.ImplInvocationHandler.invoke(ImplInvocationHandler.java:126)
11/04/07 17:57:44 at $Proxy16.Test(Unknown Source)
11/04/07 17:57:44 at testchangedescriptors.runtime.MyWebService1SoapHttp_Tie.invoke_Test(MyWebService1SoapHttp_Tie.java:59)
11/04/07 17:57:44 at testchangedescriptors.runtime.MyWebService1SoapHttp_Tie.processingHook(MyWebService1SoapHttp_Tie.java:154)
11/04/07 17:57:44 at oracle.j2ee.ws.server.StreamingHandler.handle(StreamingHandler.java:297)
11/04/07 17:57:44 at oracle.j2ee.ws.server.JAXRPCProcessor.doEndpointProcessing(JAXRPCProcessor.java:413)
11/04/07 17:57:44 at oracle.j2ee.ws.server.WebServiceProcessor.invokeEndpointImplementation(WebServiceProcessor.java:349)
11/04/07 17:57:44 at oracle.j2ee.ws.server.JAXRPCProcessor.doRequestProcessing(JAXRPCProcessor.java:277)
11/04/07 17:57:44 at oracle.j2ee.ws.server.WebServiceProcessor.processRequest(WebServiceProcessor.java:114)
11/04/07 17:57:44 at oracle.j2ee.ws.server.JAXRPCProcessor.doService(JAXRPCProcessor.java:134)
11/04/07 17:57:44 at oracle.j2ee.ws.server.WebServiceServlet.doPost(WebServiceServlet.java:177)
11/04/07 17:57:44 at javax.servlet.http.HttpServlet.service(HttpServlet.java:763)
11/04/07 17:57:44 at javax.servlet.http.HttpServlet.service(HttpServlet.java:856)
11/04/07 17:57:44 at com.evermind.server.http.ServletRequestDispatcher.invoke(ServletRequestDispatcher.java:713)
11/04/07 17:57:44 at com.evermind.server.http.ServletRequestDispatcher.forwardInternal(ServletRequestDispatcher.java:370)
11/04/07 17:57:44 at com.evermind.server.http.HttpRequestHandler.doProcessRequest(HttpRequestHandler.java:871)
11/04/07 17:57:44 at com.evermind.server.http.HttpRequestHandler.processRequest(HttpRequestHandler.java:453)
11/04/07 17:57:44 at com.evermind.server.http.AJPRequestHandler.run(AJPRequestHandler.java:302)
11/04/07 17:57:44 at com.evermind.server.http.AJPRequestHandler.run(AJPRequestHandler.java:190)
11/04/07 17:57:44 at oracle.oc4j.network.ServerSocketReadHandler$SafeRunnable.run(ServerSocketReadHandler.java:260)
11/04/07 17:57:44 at oracle.oc4j.network.ServerSocketAcceptHandler.procClientSocket(ServerSocketAcceptHandler.java:239)
11/04/07 17:57:44 at oracle.oc4j.network.ServerSocketAcceptHandler.access$700(ServerSocketAcceptHandler.java:34)
11/04/07 17:57:44 at oracle.oc4j.network.ServerSocketAcceptHandler$AcceptHandlerHorse.run(ServerSocketAcceptHandler.java:880)
11/04/07 17:57:44 at com.evermind.util.ReleasableResourcePooledExecutor$MyWorker.run(ReleasableResourcePooledExecutor.java:303)
===========================================================================================

Hod said...

Hello Chintan Shah,

I encounter the same problem you had and I tried your java code to add the property handleTopLevelFault using the command:

configurationsDescriptor.addPropertyValue("handleTopLevelFault",appropriateValue);

Usually the code works except the case there is no
configurations tags

in the bpel.xml - then we gets java.lang.NullPointerException.

Do you know how to add configurations to the descriptor using the BPEL Java API?
(We didn't found any example on the web or documentation about it)

Thanks,
Hod.

Hod said...

Hello Chintan Shah,

In Addition to what I have posted before, to be more clear:

We gets java.lang.NullPointerException on the line:

configurationsDescriptor.addPropertyValue("handleTopLevelFault","true");

because there is no configuration in the Descriptor.
if we creating the configuration tag in bpel.xml and deploying the process, the line
configurationsDescriptor.addPropertyValue("handleTopLevelFault","true");
works.

Thanks,
Hod

Chintan Shah said...

Hello Hod,

You can try following:

ProcessDescriptor processDescriptor = bpelProcessHandle.getDescriptor();
ConfigurationsDescriptor configurationsDescriptor = processDescriptor.getConfigurations();
if( configurationsDescriptor == null ) {
configurationsDescriptor = new ConfigurationsDescriptor();
processDescriptor.setConfigurations(configurationsDescriptor);
}


Let me know, I can send entire code if that helps you.

Hod said...

Hello Chintan,

Thank you very much for your help - it works! :-)

1. After we added the new property handleTopLevelFault=true we have notice that it can not be updated from the bpel console - only using the API.
Do you know why or how to fix it?

(Note that only properties we have deployed using JDeveloper deployer or Ant can be updated from console and those we have added using the API can not be updated.)

2. Do you know the command to remove property (such as handleTopLevelFault)?

Thanks,
Hod.