Saturday, 2 September 2017

Transaction Management in Oracle SOA (BPEL)

Background

Transaction Management ?? .. oophch .. a big concept.  Let me simplify it based on my understanding and practical experience in Oracle SOA  (especially in BPEL or BPMN).  In this blog, I am providing details about my approach of using Oracle BPEL or BPM for below transaction scenarios -

  • Multiple DB-Transactions invoked by Oracle BPEL process, where all these DB invocations are related to XA Datasources .
  • Multiple DB and Non-DB Transactions invoked by Oracle BPEL Process, where all these transactions are related to heterogeneous applications.
Multiple Database (XA) Transactions as a single transaction-unit:

Before directly jump into Oracle BPEL, lets look at the procedural language approach (example:  c or plsql or cobol or cics or imsdc). Lets take plsql or Pro*c, in which transactions are grouped in to "save points" and stored/wiped as a single unit to/from the database. That means, if there is a system/business exception/error then, that particular transaction unit is either rollback or committed up to that savepoint based on the functionality defined in that program (exception handler).   The same concept can be delivered thru Oracle bpel. 

  • There are many ways we can set the savepoint in Oracle bpel. The savepoint equivalents in Oracle BPEL are "catchpoint()", "idempotent=false" property activities and some activities like invoke, receive, reply, onMessage, wait, alarm.  Note: in this remaining post, I will refer these activities as "savepoint-activities".
checkpoint() code in javaexec activity is:

<bpelx:exec name="javaCallout" language="java" version="1.4">
     <![CDATA[
     checkpoint();
     ]]>
</bpelx:exec>

idempotent property on Partner link:
  • Here the catch is - whenever bpel-pm (BPEL Process Manager) reaches a savepoint-activity, it issues a "commit" to the transaction-context of that component (bpel process) to store the state of that process in FMW database (up to savepoint) and keeps a savepoint (but, where as in plsql savepoint is just a label).  Note: In Oracle bpel, storing the state of bpel-process is called "dehydration" (which is nothing but "serialization" of an object state in java programming language).  
  • So, all transactions associated to that specific processes transaction-context are get committed  accordingly (That means, bpel-pm does not explicitly/individually commits "SPECIFIC" db-transactions related to db-adapters or any activities, instead it issues a commit to store its state which internally commits all the transactions associated to that global-trx-context).
  • In a bpel-process, if "idempotent" property of db-adapter-partner-link is "false" then the invoke-activity associated to that partner-link works as a "save point".  If "idemponent" flag is "true" then, that activity does not works as either savepoint or commit.
Now take below example:  Below bpel-process is inserting two db-records to two different tables thru different partner links.

bpel-process -> 
----call1ToDBCall -> Partnerlink -> datasource -> jndi
----call2ToDBCall -> Partnerlink -> datasource -> jndi

case1:  Above both partnerlink's "idempotent" property is "true" (that means both are in global-trx-context). if any issue occurs (example: unique constraint error) in any of database call then,  bpel-pm will rollback both transactions (even though both transactions are related to different tables, different partner links, and different databases). 

Note: Make sure that both datasources are XA-Transaction type.

case2: call1ToDBCall's partnerlink "idempotent = true"
call2ToDBCall's partnerlink "idempotent = false"  then
If any issue occurs in call2ToDBCall (that means first transaction, call1ToDBCall went well) then, bpel-pm will rollback only the call2ToDBCall.

Note: Make sure that both datasources are XA-Transaction type, and dehydration at call1ToDBcall is successful.


Heterogeneous transactions in a single transaction unit:

Above mentioned all rules are applied to this scenario (Heterogeneous transactions thru a single transaction unit).

The only catch here is, Heterogeneous transactions may involve with flatfiles, XA-Based databases, non XA-Based databases, third party applications, webservices and many more.  Now the point here is, how we can bring all these applications, transactions, databases bring together as a single transaction unit?  What is the best way to rollback or commit these XA-based, non-XA Based transactions?  

Answer is little tricky, simple and complex too.  

As mentioned in the previous section, bpel-pm commit or rollback only the transactions those are part of that specific component-trx-context "and" part of "XA based datasources".  That means, if any of the application datasource is not an XA Datasource then, it does not comes under the rollback or commit. 

In BPEL, "compensation handlers" provides a flexibility to rollback or reverse the transactions for business or/and system exceptions. Compensation handler functionality is a kind of "catch" block in Java programming language. Using this compensation handlers, programmatically we can rollback the transactions.

Compensation handlers are associated at "scope" level.  
  • Usually, bpel engineers, writes the programatic rollback code in "compensation handler" of bpel-scope to reverse the transactions executed of that specific scope.  
  • "Compensation handlers" are not triggered automatically  rather they need to explicitly invoked using "compensate" activity., which can only be invoked from within a fault-handler or another compensation handler.
  • When the "compensate" activity (which is invoked from fault-handler of that scope) is executed, it will only invoke the "compensation handlers" of that particular scope associated to that fault-handler. 
  • If "compensate" activity at process level is invoked then, it will only execute the compensation handlers for the top-level scopes. The compensation handlers will only be invoked for those scopes which have completed successfully and will be invoked in the reverse order of completion. That means, the most recently completed scope's compensation handler is invoked first, and then the next most recent and so on.
  • So the bpel-process flow looks like this -
bpel-process
-- scope 
----activites 
----compensationhandler
----faulthandler 
------- catch 
----------this catch calls "compensate" activity
which will autometically calls the code (or activities) included in "compensation handler" associated to this scope.



Points to note for handling transactions related to multiple applications/partner-links thru BPEL.
  • If Service (bpel-process or composite) "A" invokes Service "B", and  Service B's transaction participant type = "NEVER" then,  Service "B" always runs in its own transaction and never comes under Service "A" transaction.   See the attached screen shot for the "transaction participant type" property.

  • If Service B Transaction participant type is "SUPPORT"  then,  Service B is ready to be part of Service A Transaction.
  • If Service B Transaction participant type = "MANDATORY" then, Service B uses the Service A transaction scope, if Service A transaction is not available (due to Service A partner link properties) then, Service B creates its own transaction.
  •  In Service A, if "Idempotent" property at the ServiceB-partner link is set to false, then Service A and Service B runs in different transaction units.
  • Even though Service A and Service B are in agreement to use same transaction, but Service B is not a part of XA Type transaction source then, BPEL-Engineer needs to write the code in Compensation handler to rollback the transactions based on business requirement and fault-handlers

No comments:

Post a Comment