1. Problem
You are building an orchestration process that contains actions that must complete together as a group or fail as a group.
2. Solution
BizTalk supports the notion
of completing small units of work following the Atomicity, Consistency,
Isolation, and Durability (ACID) transaction model. The Atomic Scope
shape implements the ACID transaction model. Atomic scopes are the most
flexible and restrictive of the transaction models in BizTalk. The use
of an atomic scope within BizTalk ensures that a group of steps either
succeeds or fails together. The following instructions outline the steps
required to create and configure an atomic scope.
Open the project containing the orchestration that will contain the atomic scope transaction.
Verify the Transaction Type property of the orchestration is set to Long Running. This is required for orchestrations containing atomic scopes.
Select
and drag the Scope shape from the BizTalk Orchestrations section of the
toolbox to the appropriate location within the orchestration.
NOTE
Atomic scopes may not contain nested Atomic Scope or Long Running Scope shapes.
Select the Scope shape, and update the properties as follows.
Change Transaction Type to Atomic.
Change Compensation from Default to Custom if your scope will contain a compensation handler.
Change Isolation Level to the correct value.
Change Name if desired.
Set the Report To Analyst property. Leave the property as True if you would like the shape to be visible to the Visual Business Analyst tool.
Change the Retry value from True to False if you do not want the Scope shape to retry in the event of a failure. The Retry value must be set to True if you plan on throwing an exception to cause the atomic scope to retry. However, setting the value to true does not mean the atomic scope will retry by default.
Change the Synchronized value from False to True if you are using the Atomic Scope shape within a Parallel Actions shape and manipulating the same set of data.
Change the Timeout
value if desired. Scope timeouts indicate the period of time to wait
(in seconds) before the transaction fails. Atomic scopes that contain a
timeout value will stop the transaction and be suspended if the timeout
value is reached.
Change the Transaction Identifier if desired.
Add the appropriate orchestration actions to the Atomic Scope shape.
3. How It Works
BizTalk supports the ACID model by providing the following features:
Atomicity: Atomic Scope shapes guarantee all actions within the Scope shape are either performed completely or not performed at all.
Consistency:
System properties (messages and variables) are preserved through the
transaction. In the situation where an atomic scope cannot be committed
and the system properties are updated, the system properties are rolled
back to their previous state.
NOTE
All variables,
regardless of whether they are local to the scope or global to the
orchestration, will be rolled back to their previous state when an
atomic scope fails.
Isolation: Each atomic scope allows controlled visibility to other scopes' and transactions' data.
Durability:
Once an atomic scope has been committed, the only way the action can be
undone is through the use of a BizTalk compensation handler.
3.1. Atomic Scope Considerations
Atomic scopes are extremely
useful, but there is an associated cost with the use of any
transactional model inside an orchestration. Consider the following when
deciding whether to use an atomic scope:
Atomic scopes
cannot contain a send and a receive port that are referencing the same
two-way request/response orchestration port. For example, if you are
referencing an HTTP/SOAP port in your orchestration, you cannot have the
Send and Receive shapes in a single Atomic Scope shape. Additionally,
you cannot have Send and Receive shapes that implement the same
correlation set within the same Atomic Scope shape. The rationale for
this is that as soon as context has left the orchestration (a message is
sent via a Send shape), the atomic scope action is complete, and a
response cannot be matched to the request.
If
an Atomic Scope shape contains a Send, Receive, or Start Orchestration
shape, BizTalk will wait to perform those actions until the scope has
been committed. BizTalk considers the boundary of the transaction to be
the point that a message has been committed to the BizTalk MessageBox.
A
single atomic scope is not that expensive in the context to processing
of an entire orchestration. However, the use of multiple atomic scopes
can be expensive because BizTalk sets a checkpoint before and after an
atomic scope is executed. Consider ways to combine multiple atomic
scopes into fewer atomic scopes. The checkpoint takes place so that the
orchestration can be resumed if it is suspended due to an exception in
the atomic scope.
NOTE
Think of a checkpoint as
BizTalk serializing its current processing state to persist and prepare
for a rollback in the case of an exception in the atomic scope. The
serialization and persistence of the current processing state reduces
performance incrementally. The more atomic scopes in an orchestration,
the more points of persistence that will be created and the greater the
overall degradation in the performance of the orchestration.
An object that is not serializable (does not implement the ISerializable interface or is not marked with a serializable attribute) must be in an atomic scope. For example, if you are using the XmlNodeList object, the variable must be declared local to the scope and referenced within the Atomic Scope shape. The XmlDocument data type is an exception to this rule.
Using
an Atomic Scope shape to perform multiple send operations does not
guarantee that the send operations will be rolled back in the case one
send fails. For example, if you have two Send shapes each sending a
message to a SQL database, if there is a failure in one or both SQL
databases, the Atomic Scope shape does not guarantee that the data will
be backed out from either database call. BizTalk considers the boundary
of a transaction to be the point that a message is committed to the
MessageBox. True rollbacks are guaranteed only in true Microsoft
Distributed Transaction Coordinator (MSDTC) transactions.
3.2. Atomic Scope Benefits
Even though atomic scopes are
the more restrictive of the two transaction models, they offer
significant benefits over the use of long-running scopes. Atomic scopes
allow the specification of an Isolation Level property, as follows:
Specifying Serializable means that concurrent transactions will not be able to make data modifications until the transaction is committed.
Specifying Read Committed means that the existing transaction is prevented from accessing data modifications until the transaction is committed.
Specifying Repeated Read means that read locks are required until the existing transaction is committed.
Atomic scopes also implement a retry capability that is enabled through the use of the Retry flag. An atomic scope will retry if the Scope shape's Retry property is set to True and at least one of the following exceptions occurs:
Microsoft.XLANG.BaseTypes.RetryTransactionException
is thrown or in the event that BizTalk cannot commit the transaction.
Additionally, all variables will be reset to their state prior to entry
of the scope.
Microsoft.XLANG.BaseTypes.PersistenceException occurs due to BizTalk's inability to persist state.
3.3. Exception Handling
One challenge to using atomic
scopes is the fact that you cannot have an exception handler on the
Atomic Scope shape itself. Atomic scopes are defined to either succeed
or fail, hence there is no direct need to have an exception handler. In
the situation where an exception should be caught in an error handler,
the items that cause an exception can be enclosed in a nontransactional
scope (with an error handler) inside the atomic scope.
Consider the
following scenario: you must pass a nonserializable object to a custom
assembly that, in turn, makes a database call. You want to catch any
communication exceptions and force the atomic scope to retry. One option
for this scenario would be to implement an atomic scope to manipulate
the nonserializable object and within that Atomic Scope shape, include a
nontransactional Scope shape with an error handler that will throw a Microsoft.XLANG.BaseTypes.RetryTransactionException. This scenario would allow you use a nonserializable object and force a retry in the case of a communication problem.
NOTE
When throwing a RetryTransactionException to perform a retry, validate that conditions have changed so that you do not continually throw a RetryTransactionException and create an infinite retry loop.
3.4. Compensation Handling
Atomic Scope shapes (as
well as other Scope shapes) support the notion of compensation to
facilitate undoing a logical piece of work regardless of the successful
commit. Suppose that the atomic scope executes and commits successfully,
but there is a business-error problem with the message data. The atomic
scope, from a technical aspect, executed and committed correctly.
However, due to the business validation failing, the transaction must be
undone. Compensations allow definition of a process that details how
the previously committed atomic transaction is to be rolled back.
The structure of a
compensation handler is similar to that of an exception handler but
functionally different. BizTalk will use the default compensation
handler if no custom compensation handler is defined. The default
BizTalk compensation handler calls the compensation blocks of any nested
transactions, in reverse order of completion. Compensation handlers
must be called explicitly, unlike error handlers, through the use of the
Compensation shape. A common use for a compensation handler is to
create a message that indicates business data needs to be backed out of a
specific system or process.
3.5. MSDTC Transactions
An Atomic Scope shape
behaves like an MSDTC transaction but is not an explicit DTC transaction
by default. To clarify, if you send a message to SQL Server via the SQL
adapter, the actions performed in the SQL call will not roll back, and a
compensation handler is required to back out any committed changes. The
reason a compensation handler is required is due to the SQL adapter not
enrolling in an explicit DTC transaction.
Atomic scopes do support
the use of a DTC transaction as long as the objects referenced in the
scope are serviced components (COM+ objects) derived from the System.EnterpriseServices.ServicedComponents
class. Additionally, the isolation levels must agree and be compatible
between transaction components and what is specified in the atomic
scope. The atomic scope does not require a configuration value to be set
on the shape itself, as it will automatically enroll in an MSDTC
transaction if possible.
Listing 1 serves as an outline for what to include in your assembly for creating a serviced component. Your assembly must reference System.EnterpriseServices and System.Runtime.InteropServices (for the Guid attribute reference). Verify that your component is registered in the Global Assembly Cache (GAC) (for example, using gacutil) and that you also register the component in COM+ (for example, using regsvcs).
Example 1. Serviced Component
using System; using System.EnterpriseServices; using System.Runtime.InteropServices;
namespace MSDTCTestLibrary { /// <summary> /// Summary description for Class1. /// </summary> /// [Guid("9943FB26-F4F5-4e80-B746-160AB9A6359E")] [Transaction(TransactionOption.Required)] public class ClassMSDTCTest : ServicedComponent { public ClassMSDTCTest(){}
public String Test() { try { // Commit the transaction ContextUtil.SetComplete(); return "Test"; } catch (Exception ex) { // Abort the transaction ContextUtil.SetAbort(); return ex.ToString(); }
}
} }
|