SOA Transaction Boundaries – Part 1

We will try to understand the behavior of SOA transaction  boundaries by creating simple BPEL process and gradually adding functionality to it.

At the very basic, every BPEL process executes in the context of a transaction. It either creates a new transaction or joins an existing transaction.

Let us a create BPEL process which consumes message from a JMS Queue.

Environment

Oracle SOA 11.1.1.7.8  on Windows 7 64 bit OS.

DB Table

CREATE TABLE SOURCETBL(SEQ NUMBER NOT NULL,NAME VARCHAR2(20 BYTE),FLAG VARCHAR2(20 BYTE) NOT NULL,EMAIL VARCHAR2(200 BYTE),CONSTRAINT SOURCETBL_PK PRIMARY KEY(SEQ)ENABLE);

CREATE TABLE TARGETTBL(SEQ NUMBER NOT NULL,NAME VARCHAR2(20 BYTE),FLAG VARCHAR2(20 BYTE) NOT NULL,EMAIL VARCHAR2(200 BYTE),CONSTRAINT TARGETTBL_PK PRIMARY KEY(SEQ)ENABLE)

DataSources & JNDI Names

 

Name Datasource JNDI DBAdapter JNDI
FirstXA jdbc/FirstXA eis/db/FirstXA
SecondXA jdbc/SecondXA eis/db/SecondXA
FirstNonXA jdbc/Firstnonxa eis/db/FirstNonXA
SecondNonXA jdbc/Secondnonxa eis/db/SecondNonXA

 

JMS Setup

Following JMS resources are used in the examples.

Queue NonXA CF XA CF Adapter XA JNDI Adapter Non XA JNDI
jms/MyQ jms/MyQNonCFXA jms/MyQCFXA eis/jms/XA eis/jms/nonXA

Queue is configured with following “Delivery Failure” Options.
Redelivery Delay Override: 10000
RedeliveryLimit: 1
Expiration Policy: Discard

Sample Schema

<?xml version="1.0" encoding="windows-1252" ?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
 xmlns="http://xmlns.oracle.com/ex/emailrec"
 targetNamespace="http://xmlns.oracle.com/ex/emailrec"
 elementFormDefault="qualified">
 <xsd:element name="ERecord" type="ERecordType"/>
 <xsd:complexType name="ERecordType">
 <xsd:sequence>
 <xsd:element name="seq" type="xsd:integer" />
 <xsd:element name="name" type="xsd:string" />
 <xsd:element name="email" type="xsd:string" />
 </xsd:sequence>
 </xsd:complexType>
</xsd:schema>

BPEL Process with JMS Adapter

  • Create a SOA Application.
  • Add JMS Adapter to consume messages based on above schema. Use Non-XA JNDI to start with.
  • Create a BPEL component based on wsdl created as part of above step and wire it with JMS Adapter.

Create BPEL Process

  • In the BPEL process just add an “Empty” activity.

SOA Composite

Deploy the process.  Add the following xml message to JMS Queue

<ERecord xmlns="http://xmlns.oracle.com/ex/emailrec">
 <seq>1</seq>
 <name>Krishna</name>
 <email>kri@dom.com</email>
</ERecord>

Put Message into JMS Queue

There is nothing interesting in this base process. A bpel instance would have been created and completed.

Rollback Fault

As part of the bpel flow, let us throw a Rollback fault. Let us see whether our message is rolled back to JMS queue.

Modify BPEL to have a rollback fault (after  the empty activity) and deploy the process.

Throw Rollback Fault

Add a message to JMS Queue.

Audit Trail of Rollback Fault

Audit trail shows that the transaction was rolled back. However, if we see our JMS queue, our message is not rolled back to the queue.

MsgCntInQ

Is this because we used non-xa?.

Using XA JNDI

Modify the JMS jca file to have XA JNDI instead of non-xa JNDI and redeploy the process. The result is same as before. Transaction would have rolled back , but we don’t see messages back in our queue.

Does it mean the rollback is not doing what it is supposed to do?.

Let us add one more action, inserting into DB table , as part of the BPEL flow.

  • Add a DB Adapter to insert or merge into the table.
  • use XA JNDI
  • Add an invoke before “Throw” to call  DB Insert.
  • Add a assign/transform activity before invoke to initialize variable for DB insert.

DBAdapter Insert

Deploy the process and add a message to the queue. Audit trail will show that “DB Insert” was completed successfully and transaction was rolled back.

Rollback with DBInsert

If we look at the table, there will be no record, which means “rollback” is doing what it is supposed to do. It roll backed the insert. However, the rollback didn’t restore the message back in JMS queue. So, we can conclude, DB Insert happens in a separate transaction and JMS dequeuing happens in a separate transaction.

The above results implies

  • There will be two transactions.
  • JMSAdapter transaction – which gets committed even before BPEL executes
    This is due to the setting async.persist which will put the message in dlv_message table and commit the transaction. BPEL invoker threads will pickup from dlv_message and initiate BPEL, which will run in new transaction.
  • BPEL flow – which runs in new transaction.

SOA Transaction and Boundaries

When rollback fault is thrown, only Transaction 2 is rolled back(no record in DB Table). However, transaction 1 will be committed. That is the reason, we don’t see the message back in the queue. So,if we use “aysnc.persist” for “oneWayDeliveryPolicy”, Bpel Engine will execute activities in two transactions as shown in above diagram.

Single Transaction

If we want one transaction instead of two, we need to set “oneWayDeliveryPolicy” to sync.With this setting . DLV_Message table is not used. JMSAdapter and BPEL will get executed in the same thread.

Change “oneWayDeliveryPolicy” to “sync”. Redeploy the process and add a message to Queue.

This time, because of rollback fault, you can find that message is rolled back to JMS queue and retried.

Actually, with this setting also, it will be still two transactions as shown in below diagram.

SOA Transaction Boundaries

The reason for above behavior is BPEL always starts new transaction. If there is any existing transaction, it suspends that one. Suspended transaction will resume after the current bpel flow completes.

JMSAdapter Transaction (Txn 1) will be suspended and BPEL starts a new transaction (Txn 2) to execute BPEL activities. When Rollback fault is thrown, Txn2 is rolled back. JMSAdapter gets a remote fault and since it doesn’t handle the fault, Txn 1 also will be rolled back.  We can observe these faults in audit trail

Rollback and Remote Fault

To make BPEL to participate in existing transaction, instead of creating new one (which is default behaviour), we need to set “bpel.config.transaction” property to “required”.

If value is “required”, BPEL will participate in existing transaction , if any available. If not it will start a new transaction.

If value is “requiresNew” (default value), BPEL will create new transaction. If any existing transaction is available, that will be suspended.

Add “bpel.config.transaction” property to composite.xml with value “required” and deploy the process.

 <component name="SoaTxBPEL" version="2.0">
 <implementation.bpel src="SoaTxBPEL.bpel"/>
 <property name="bpel.config.transaction" type="xs:string" many="false">required</property>
 <property name="bpel.config.oneWayDeliveryPolicy" type="xs:string" many="false">sync</property>
 </component>

With this setting , Txn boundary will be like below and everything will get executed in single transaction.

Single Transaction

When everything happens in a single transaction, and a rollback fault is thrown, we can not catch it inside bpel , even if we have a catch block.

Modify BPEL process to have a catch all and deploy it. In Audit trail we can see that though a “rollback” fault was thrown and catchall block exists, catchall branch doesn’t get executed.  BPEL fault handling, as with other activities, happens in the context of transaction. When the existing only transaction is rolled back, BPEL will not be able to catch or handle faults.

In all these, we haven’t seen single record getting committed in the DB. If we want to commit the DB transaction and at the same time, we need to roll back messages in queue, we need to move DB Insert out of transaction . Use Non-XA JNDI for DB Insert. This will ensure DB Insert operation doesn’t participate in distributed transaction and gets committed irrespective of rollback fault.

As part of this post we saw how Transaction boundaries are determined when JMSAdapter and BPEL components are used and how values of bpel.config.oneWayDeliveryPolicy, bpel.config.transaction influences boundary demarcation.  In next post (SOA Transaction Boundaries – Part 2), we will see how these values influence transaction boundaries when two bpel components are used.

Leave a Reply

Your email address will not be published. Required fields are marked *