Monday, August 25, 2008

Handling Exceptions: Creating and using fault policies

Back then...and now
Prior to patch 10.1.3.3, we had to write fault handling code for each and every BPEL process we created. This was done at design time, and more often than not there was a great deal of overlap in the fault handling code for different processes. In essence, we merely ended up writing the same code over and over again. Reusability was thus non-existant as far as fault handling was concerned.

With the 10.1.3.3 patch things have turned over a new leaf. Now, you have the option of creating fault policies(fault handling) that can be applied to an entire domain. Besides, you can bind these policies to a BPEL process at different levels - partnerlink,port type, process and domain. The framework will use the binding in order of the following priority :
  • bpel.xml
  • policy defined on the server
The reader must note that a fault policy defined on the server will always takes precedence over one that is defined in the BPEL process(catch/catchall blocks), if at all one exists.

Designing a fault policy
A fault policy file defines fault conditions and their corresponding faultrecovery actions. Each fault condition specifies a particular fault or group of faults, which it attempts to handle, and the corresponding action for it. A set of actions is identified by an ID in the fault policy file. Please bear in mind that you can have only one fault-policy for a domain and it must be under SOA_ORACLE_HOME\bpel\domains\domain_name\config\fault-policies. You need to create the fault-policies directory under config as it does not exist by default.

The fault-policy file essentially consists of two sections - condition and action. The condition section is based on a faultName. Each condition has an optional test section and a mandatory action section. The test section tests the occurence of a particular fault and upon the test being true(when that fault has indeed occured ) an action is taken which again is defined in the same file. Several actions can be configured for a particular faultName.

For the purpose of demonstration I have created a fault-policy file which is as follows:
<?xml version="1.0" encoding="UTF-8"?><faultPolicy version="2.0.1" id="SankashPolicy" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.oracle.com/bpel/faultpolicy" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&gt;
<Conditions>
<faultName xmlns:bpelx="http://schemas.oracle.com/bpel/extension" name="bpelx:remoteFault">
<condition>
<action ref="ora-retry"/>
</condition>
<condition>
<action ref="ora-terminate"/>
</condition>
</faultName>
</Conditions>
<Actions>
<Action id="ora-retry">
<retry>
<retryCount>2</retryCount>
<retryInterval>2</retryInterval>
<exponentialBackoff/>
</retry>
</Action>
<Action id="ora-terminate">
<abort/>
</Action>
</Actions>
</faultPolicy>

If you scroll down to the conditions section you will notice that I am testing for remotefault. If a remoteFault does occur, my remedial action is to retry the connection twice at an interval of 2 seconds. If that does not yeild any result, the final action is terminate the process altogether.

Associating a fault policy
Now that we are done with creating the fault policy, we will see how to bind the policy with a process. As already mentioned the binding can occur at partnerlink, port type, process and domain level. To associate a policy at the process level you need to create the bindings in the bpel.xml file. However, if you want it at the domain level you need to specify the bindings in the fault-bindings.xml under SOA_ORACLE_HOME\bpel\domains\domain_name\config directory. Whichever association you want, the bindings are defined as follows:

<faultPolicyBindings version="2.0.1" xmlns="http://schemas.oracle.com/bpel/faultpolicy" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&gt;
<process faultPolicy="SankashPolicy"/>
<partnerLink faultPolicy="SankashPolicy"/>
</faultPolicyBindings>

In order that the BPEL process manager picks up the policy you created just now, restart the server.

Use case
To ascertain that the policy is indeed active, create a synchronous BPEL process(wihtout any catch/catchall) that simply calls a java web service. Compile and deploy it. Verify that it executes successfully. Now log in to the enterprise manager console and undeploy the web service that the process was calling. Now, again initiate the process. Open the Activity Audit Trail for the instance. Observe that the process gets terminated. See screenshot below.



Remember nowhere in the process we had written code to terminate it upon the occurence of a remote fault. Evidently, the policy must have caused it to do so.

No comments: