Saturday 2 September 2017

Managing Faults/Exceptions in Oracle SOA/BPEL

Background

One of the key factor in any successful integration (or integration-platform) is its robust/scalable and easy to maintain error-handling framework. 

Handling exceptions in SOA/BPEL is very much similar to handling exceptions in any other 4GL OOP Languages approach. The additional benefit or a cool feature introduced in SOA11g is its "Fault-management" framework, which allows to define a loosely coupled "error handling framework" at BPEL Application/composite/component level. But, managing exceptions and faults depends on various factors like exception type such as business or run-time, integration-patterns such as synchronous or asynchronous, exception handlers such as retry or abort or human intervention or custom (java classes) handler etc.  Lets go in detail..

Details

  • Exceptions are two types : 1)- Business Exceptions 2)- System exceptions. 
  • Business Exceptions are checked exceptions, System exceptions are similar to unchecked exceptions in java.
  • Like Java, In BPEL, "business" exceptions (checked exceptions) needs to be defined and thrown by developers, where as "system" exceptions usually thrown at runtime (developer can throw pre-defined system exceptions programmatically). These exceptions can be handled within the bpel-process or at client or at "fault-management" level.
  • Like java (handling exceptions at block level, method level and class level),  BPEL is also having functionality to create and handle catch at  "scope level" and "process level".

Different fault/exception handling patterns


  1. Asynchronous process to return both Response and Fault messages.
  2. WSDL based BPEL process with Faults defined in its WSDL (only works for Synch process)
  3. BPEL Process with Exceptions defined and thrown in its "throw" activity (for both Synch & Asynch)
  4. Exception handling thru Fault-management framework (for both Synch & Asynch)

1. Asynchronous process to return both RESPONSE and FAULT messages

  • Approach#1: The simplest, easiest (and widely accepted) approach is - Asynchronous service's response message (used in call-back activity) must have three parts, those are  1)- result 2)- Input message 3)- Fault. If there is "no" fault in the process then, "result" contains the output of that specific service/process, and "fault" contains empty data. If there is a fault then, "result" contains empty elements and "fault" part contains (captures) actual fault-message/code/name, where as "input message" part always holds "input/request/received message" (this "input message", usually used for correlating the input and output calls in async service).  If your business needs some more flexibility than above approach and likes to get separate "result" and "fault" messages appropriately from the "called asynch process", then follow below approach.
  • Approach#2: As mentioned in the beginning, asynchronous services don't explicitly support the functionality of "faults".  Basically, Asynchronous service receive and callback/sends the messages thru different dedicated ports.  So, the fault-message (other than actual result) cannot use the port defined and dedicated for "actual/original" result-message.  So, the big question here is, how can we send different messages to "calling process" thru different ports in Asynch BPEL-Process?? Follow below steps for tricky solution.
  • step1: Define an Asynch service (which have "Receive" activity to receive request-message from client  and "Callback" activity to send response to client) with "additional" "callback/invoke" activities to send the fault to "calling process".
  • step2: These "additional" callback/invoke activities needs to invoke the "partnerlinks" associated to "Fake" wsdls (or fake bpel services). That means, these "additional" partner links needs to be created on top of a "fake" wsdl or "fake" bpel-service.  Here, "fake" means they doesnot perform any service or operation, just empty services/wsdl, and above (step1) created "additional" invoke activities sends the faults to these "fake" partnerlinks, which internally "re-directs" the messages to calling-process. How ??   Refer below step3 and 4.
  • step3: In "Asynch process" (defined in step1), make sure to update the "endURL" property of above "additional" invoke activity with the URL passed from "calling process".  Refer step : 4 and 5  for much more clarity.
  • step4: In "Asynch process" (defined in step1), make sure to create a new property to create a new variable and store the call-back url provided by "calling process" in "receive" activity. Refer step : 5 for much more clarity.
  • Note: In short, in above step1,2,3 and 4, we have created a Asynch-bpel-process with a "receive activity" to receive the request-message from "calling process", and multiple callback/"invoke" activities to send result-message and faults to "calling process".  In those multiple call-backs, one is default-call-back which sends the "original"/"actual" response, and remaining are to send "faults" and "different-results" to "calling-process".  
  • step5: Define/develop a "calling process" to call the above created "Asynch process".  Make sure that this calling processes wsdl must have two operations (or more, based on your business functionality) in the "portType", in which one is to send messages to "Asynch process" and others to support "fault" responses.  Make sure that, the additional operations defined in the "input portType" must have same and exact operation name, namespace, message name and message type defined in "fake" wsdl mentioned in step2.
  • step6: In the "calling process", define a property in the "invoke activity" (which calls asynch process) to capture the "Fault message" recipient URI (Asynch process sends the "fault message" to this URI). Also define the correlation between "invoke" activity and "receive" activites (which receives "actual result" and faults). This is important step. Refer below attached step6 screen shot.
  • Thats it.. your solution is ready for deployment.  see the screen shots for much more clarity on above steps.
Step1:Create "Asynch process" with "invoke" and "callback" activities (in below attached screen shot, these activities are represented in blue color squares). Here, "Invoke" activity calls the partnerlink (which is defined based on a fake-wsdl) with a fault-message (programmatically bpel-process re-directs this call from fake-wsdl/fake-service to the "actual" endURL provided as a parameter to "invoke" activity).

Step2: create a fake-wsdl, and create fake-partnerlink on top of that fake-wsdl and map it to "invoke" activity. For clarity, refer below three screen shots.



Step3: Now, capture the "actual/end" URI passed from "calling process". The value of "actual/end" URI is available in "faultToAddress" property (of "Receive" activity)

Step4: Update "endURL" property of "invoke" activity with above retrieved "actual/end" URI. 

Step5: Now, create a "calling process" to call above defined (step1,2,3 and 4) "Asynch process", and make sure that the "operation" used in "calling process" (which is used to get "fault-messages") must have exact "operation name", "namespace", "message type" and "message name" defined in "fake-wsdl" (for clear details, compare the "operation" element defined in step1 wsdl with below step5 wsdl). 

Step6: Define a property called "replyToAddress" in calling process "invoke" activity to hold the return/result endURI.  "Asynch process" uses this URI to send/call-back the "fault message".

Stpe6: In "calling" process, make sure to define a pick activity with two "onMessage" events, in which one to receive the default call-back, and other to receive the "fault message" thrown by "Asynch process". As this is Asynch integration, make sure to "correlate" the response/request messages of onMessage activities with "invoke" activity.

Pick activity screen shot
onMessage Activity for default callback

onMessage Activity to receive "fault message"

Thats it .. deploy the complete solution (calling process, asynch process, fake wsdl/service) to weblogic.  Here, "calling process" invokes "Asynch process" with replyToAdress property.  When a fault is raised  "Asynch process" invokes (or call-backs) the "replyToAddress" URI (which is passed from "calling process" to "asynch process") with fault message.  If every thing goes well then, "Asynch process" uses its "regular" call-back activity to send "response" to "calling process".

2. WSDL based BPEL process with Faults defined in its WSDL (only works for Synch process)

  • Business exceptions can be defined and thrown at bpel-activity/scope or can be declared in the bpel-process wsdl and "thrown" at activity level.  
  • If the process is synchronous + wsdl based + having fault-mesages in that wsdl then, make sure to define fault-variables in bpel-process with exact type of fault-messages defined in "wsdl".
  • This approach only works for "synchronous" BPEL process (cause, asynchronos process returns the response or faults using different "port", so we need to do some tricky programming to return both "faults" and "response" from a single Asynch process, which I have discussed in the above asynch solution).
Step0: Above schema is used in the wsdl. Note the "fault message"
Step1: wsdl
Step2: Synch process is designed based on above wsdl. Note the "ppkFault", throw activity

Step3: Notice the fault variable defined in at bpel-process level.
Step4: Throw activity "must" use above created fault variable and setups (namespace, faultname) defined in WSDL

Step5:Catch (either in process or scope catch level) must refer exact namespace, localname of "fault" defined in above step4. Thats it...  your synchronous service is ready to throw and the catch exception/fault defined in WSDL. 

3. BPEL Process with Exceptions defined and thrown in "throw" activity (for both Synch & Asynch)

  • Create a bpel service
  • Create a throw activity based on the business needs
  • Just provide (hardcode) the exception details (name space, name of the fault, fault variable) in throw activity.  thats it..
  • Works for both sync and asynch patterns.
unlike java or Oracle BPM, bpel is not having any functionality to create exceptions as separate variables/activities, instead exception is created and throned in the throw activity.
This BPEL process is created based on synchronous template/type (not based on wsdl).
Create throw activity based on business requirement (notice the setup: all these are custom and hard coded values, but these values must match the setups defined in "Catch" activity.

This catch activity setups mush match (exact match) with the setups/exception/fault defined in above "throw" activity.
thats it... you are all set to test the service.

4. Exception handling thru Fault-management framework (for both Synch & Asynch)

  • Define fault-policies.xml, fault-bindings.xml 
  • Update composite.xml to refer above fault xml files
  • Create a sync proxy service and make sure to throw the exceptions/faults defined in the fault-policies.xml
  • fault-policies.xml and fault-bindings.xml files either can be stored in mds or can be available in the same location as composite.xml.  fault-policies.xml contains the fault/exeption definitions and the actions associated to that exceptions.  These actions either can be system actions such as retry, human intervention, re-throw, abort/terminate and even custom exception handling thru java code.  fault-bindings.xml provides setting to associate the faults defined in fault-policies.xml to the "entire composite" or to specific components/references defined in the composite.
Defining fault-policies.xml (Notice PPKFault1 fault)

Define fault-bindings.xml (I have attached fault-policy at composite level)

Provide references of above two files in composite.xml

Refer the above defined fault exactly in BPEL throw activity.  

Thats it.. deploy and run the bpel process.  If a fault is raised in bpel-process then, the corresponding handler action is executed based on the setups defined in fault-policies.xml

No comments:

Post a Comment