Thursday, September 08, 2011

Working with Transactions

(From http://www.oracle.com/technetwork/articles/soa/wli-bpel-transactions-088255.html)


Introduction

Transactions have always been the center of the universe when designing any application. Transactions were easier to define and manage back when developers could to control them through code. The options may have been limited, but developers knew what to expect.
Over the last decade, through the advent of Java 2 Enterprise Edition (J2EE) and other technologies, developers were encouraged to leave transactions to the container. But for developers with a limited understanding of container-based services, this can present an obstacle.
Things can get even worse when transaction demarcations are created automatically within the container, leaving developers with a very limited understanding of what is happening.
This article is an effort to unlock the mysteries of the container-managed and container-defined transactions within WebLogic Integration (WLI) and Oracle BPEL Process Manager (BPEL PM).
A common misconception about Oracle BPEL Process Manager is that it does not support global XA transaction groups. The likely cause of this misconception is that unlike WLI, BPEL PM includes no activity specifically labeled "start transaction" or "stop transaction." Instead, a transaction group is implicitly delineated, based on the types of activities involved.
Let's start with a very simple WLI transaction example to see how it can be implemented in BPEL PM. After that we'll deal with more advanced topics, such as compensating transactions.

A simple transactional process

In this example, a process performs an update to three databases and enqueues a JMS message. All resources are XA-enabled and the process forms a global transaction.

Implementing the process in WLI

Similar to BPEL PM, business processes in WLI are transactional in nature. Every step of a process is executed within the context of a JTA transaction. A transaction ensures that one or more operations execute as an atomic unit of work. If one of the operations within a transaction fails, all operations are rolled-back so that the application is returned to its prior state. Depending on whether the business process logic is defined such that it is stateful or stateless, there may be one or more transactions within the context of a given business process.
When starting a business process, the process participates in the caller's transaction or starts a new transaction if none exists. If there are no implicit or explicit transaction boundaries, the process executes within a single transaction.
In the first example, our business process invokes four synchronous XA calls. The process is synchronous and stateless. The container manages this transaction.
WLI simple transactions
Because no implicit or explicit transaction boundaries are defined, WLI will automatically make the entire process run in a single XA transaction. If there is a problem with any of the data sources (for example, if a database is down, or the JMS queue is unreachable), and no exception handler has been defined, the whole transaction will roll back.
When building a business process in WLI, implicit transaction boundaries are formed, based on where blocking elements are placed in the process. The transaction boundaries within a business process change as nodes are added to the business process.
Implicit transactions are implicit both because their behavior is automatically determined (or implied) by the business process logic and because they are not visible in the process diagram.
Implicit transaction boundaries are formed based on where blocking elements are placed in the process. These boundaries change as process nodes are added to the business process. Additionally, a business process is stateless by default, and blocking elements that change transaction boundaries can change the process to be stateful.
The following nodes change the transactional behavior in business processes in WLI:
  • Any receive (blocking) nodes (Client Request or Control Receive nodes)
  • A Parallel group node
  • An Event Choice node
  • Existing transaction boundaries are unaffected by adding one or more nodes (within those boundaries) that do not themselves force a transaction boundary.
Illustrated below is an example of a business process with an implicit transaction. The Control Receive node is a blocking element in the business process and therefore creates a new transaction
implicit transactions
Additionally, WLI provides the ability to explicitly define a transaction by using the "Transaction" node within the WLI palette. This gives developers the ability to group certain nodes in a transaction boundary and have localized roll-back that will not affect the implicit process transaction. By incorporating the "Transaction" node into the simple example above it is possible to perform two distinct transactions instead of one. The diagram below shows the first two database updates in one transaction, and the JMS enqueue and third database update in a separate transaction.
WLI explicit transactions
By explicitly specifying a transaction scope within the WLI process, we force WLI to complete the open transaction (the transactions do not nest here) and begin a new, separate transaction. If we were to add additional steps after the explicit end of the transaction scope, they would also begin their own, new, implicit XA transaction. Nested transactions are not supported in WLI.
If the WLI process is a stateless process (sync or async), it will always execute in one and only one implicit transaction. Explicit transactions cannot be defined in synchronous processes or in stateless asynchronous processes. So, referring to the above example, simply adding the transaction node to a stateless process converted it into a stateful process.
Additionally, the following restrictions apply to explicit transactions:
  • The selected nodes must be contiguous
  • The selected nodes cannot include a Client Request or Control Receive node
  • The selected nodes cannot be inside the client request/response nodes of a synchronous process
  • The selected nodes cannot include a Parallel or Event Choice group node where including them in an explicit transaction would nest the transaction for their branches.
  • The selected nodes cannot be inside an existing explicit transaction
For more information about transaction handling in WLI, see the documentation covering Transaction Boundaries.

Implementing the process in BPEL PM

In BPEL PM, as in WLI, every BPEL process executes in the context of one or more transactions. When a process starts to execute, the process manager does one of two things with transactions:
  1. It starts a new transaction for the process.
  2. It enlists the process in an already open transaction.
BPEL uses this transaction to update process state in the database (this is called "dehydration") and also to log audit events in the database. Even if all this is turned off, the process manager will still execute processes in a transaction context. When invoked through a Web Service interface, BPEL will use the first option, since no transaction context will be available. When invoked through the Java API in a transactional environment, the process manager may use either option, depending on the parameters used in the call.
BPEL will try to squeeze as many activities into a single transaction as possible. Only a few activities actually cause the process manager to update the process state in the database and commit the transaction. A given activity does not always cause a transaction to be committed: sometimes the process may keep the same transaction context because of the properties associated with the activity.
In our simple scenario the default transactional behavior is similar to that in WLI. When a process is instantiated and there is no current transaction context, a new transaction is created. As in WLI, certain activities in BPEL will naturally delineate XA transactions and will force a transaction to end. These activities cause the state of the BPEL process to be quiesced to the dehydration store. When the process resumes from this type of activity, a new transaction will be started. The diagram below illustrates the same steps as above, as implemented in BPEL as a single, implicit transaction.
BPEL simple transactions
To perform the second use case, where we'd like to split our transaction into two separate transactions, in BPEL, we need to deliberately end the first transaction. This can be done explicitly through the use of the "checkpoint" method inside a Java Exec activity, as shown below.

<bpelx:exec name="checkpointJavaExec" language="java" version="1.4">
     <![CDATA[
     checkpoint();
     ]]>
</bpelx:exec>
In addition to "wait and receive" and other activities that cause dehydration (writing BPEL process state to the database and committing the transaction), transactions can also be committed after an invoke by setting the idempotent property on the target partner link to false. If idempotent is set to false, the invoke activity is dehydrated immediately after execution and recorded in the dehydration store. This will end the initial transaction and start a new transaction. The diagram below shows how this can be implemented.

When BPEL calls an adapter, the ESB, or another process in the same BPEL domain, it has the option to either include the target in the same transaction, or to start a separate transaction. This behavior is controlled by the transaction property in the partner link. If the transaction property value is set to participate, the callee is enlisted in the current transaction. If the transaction property is set to any other value, the callee executes in a separate transaction. This is great for ensuring that multiple database updates are included as part of the same transaction, but be aware that there is a downside.
If any callee rolls back the transaction, the current BPEL process state is also rolled back to the last commit. If there has been no commit and the process was invoked through a synchronous interaction, the process will seem to disappear from the face of the earth. To minimize the impact, the database adapter will throw an error rather than rollback the transaction — if doing so will not affect transactional integrity. (Basically, you can do one DB update without rolling back, but if you do two, an error will cause a rollback.)
One final thing to be aware of is that in BPEL, a flow activity (which is used to designate activities for parallel execution) is actually processed sequentially unless it encounters an activity that will cause the thread to be suspended. This is efficient, but defeats one of the use cases of the flow, which is to perform multiple operations in parallel to reduce service latency. BPEL provides the nonBlockingInvoke=true partner link property to cause invokes to a synchronous service to be treated internally as calls to an asynchronous service. Internally, the process waits for the message on the JMS queue, causing the transaction to be completed. At the same time, a new thread is started to perform the synchronous call and place the result in the queue. This allows the other legs of flow to execute in parallel.

Beyond XA: compensating transactions

The examples above address the behaviors when all of the resources are XA-compliant. When there are activities that are not XA-compliant, compensating transactions must be built into the process. Both WLI and BPEL provide a mechanism to do this through the use of exception handlers.
Also, BPEL includes the concept of an invocable Compensating Transaction. This is similar to an exception handler, and is defined at the scope level. However, it is explicitly invoked only by the "Compensate" activity. Compensation is intended to allow the application of reversing operations to systems that cannot participate in transactions, or when it has been decided that the systems should not operate as part of transactions. For example, a Web Service might allow inventory to be decremented, but an error makes it necessary to roll back the process. In this case, a compensation handler would be defined to call the Web Service to increment the inventory, effectively providing a reversing transaction. This allows you to define rollback activities and associate them with the code that performs the operations that may need to be reversed. This is also very useful in that it allows some exceptions to be handled without undoing all of the work.
If a scope requires a compensation handler, the service that requires compensation should be marked as non-idempotent by setting the "idempotent" property value to "false." This will cause Oracle BPEL Process Manager to start a new transaction after invoking the non-transactional resource.
The following diagram illustrates an example of the use of Compensation Handlers, and an explicit forward-based compensation model. Note the explicit call in the catchAll block of the second scope, invoking .

Key Takeaways and Recommendations

Both WLI and BPEL PM manage global XA transactions, both tools initiate an implicit transaction when the process gets instantiated, and similar activities in both WLI and BPEL force the end of transactions. Note, however, that unlike WLI, Oracle BPEL Process Manager not only allows multiple transactions to occur in an asynchronous stateful process, it also allows them to be defined in a synchronous process. With the addition of compensation, BPEL provides a standard and reliable mechanism for providing compensating transactions for non-transactional resources.
BPEL is inherently a stateful language. Oracle BPEL Process Manager uses XA transactions to manage that state, and allows XA transactions to extend beyond the boundaries of the active BPEL process.
The general rules about what causes a commit are straightforward, and the BPEL process will commit the transaction and start a new one after the following activities:
  • receive - Unless it is the first receive in the process and the process was called with a "transaction=participate" property (possibly by marking it as such in the partner link of a calling process), in which case the process participates in the existing transaction.
  • checkpoint() - Call in a Java Exec activity
  • onMessage
  • wait - For very short waits (up to two or three seconds), the process manager will not commit the transaction.
  • onAlarm
  • invoke - Only if the partner link is non-idempotent (can be marked with the "idempotent" partner link property).
  • End of process flow - Only if the process is not participating in the caller's transaction (the corollary of the receive).
The table below summarizes the transaction status when performing different activities.
Activity Transaction Status
in BPEL Process
Transaction Status
in Target Process or Adapter
Receive New Transaction N/A
Receive with Property "transaction=participate" Use Existing Transaction from Caller N/A
Invoke Synchronous Process Use Existing Transaction New Transaction
Invoke Synchronous Process with Partner Link Property "transaction=participate" Use Existing Transaction Use Existing BPEL Transaction
Invoke Synchronous Process with Partner Link Property "idempotent=false" New Transaction New Transaction
Invoke Synchronous Process with Partner Link Property "nonBlockingInvoke=true" New Transaction New Transaction
Invoke Asynchronous Process Use Existing Transaction New Transaction
Invoke Asynchronous Process with Partner Link Property "transaction=participate" Use Existing Transaction New Transaction
Invoke Synchronous Process with Partner Link Property "idempotent=false" New Transaction New Transaction
Wait < a couple of seconds Use Existing Transaction N/A
Wait > a couple of seconds New Transaction N/A
checkpoint() New Transaction N/A
Flow Use Existing Transaction for all parallel activities N/A

No comments: