WEBSITE

Programming WCF : Queued Services - Transactions

10/12/2010 3:22:22 PM
MSMQ is a WCF transactional resource manager. When you create a queue (either programmatically or administratively), you can create the queue as a transactional queue. If the queue is transactional, it is durable, and messages always persist to disk. More importantly, posting messages to and removing messages from the queue will always be done under a transaction. If the code that tries to interact with the queue has an ambient transaction, the queue will silently join that transaction. If no ambient transaction is present, MSMQ will start a new transaction for that interaction. It is as if the queue is encased in a TransactionScope constructed with TransactionScopeOption.Required. Once in a transaction, the queue will commit or roll back along with the accessing transaction. For example, if the accessing transaction posts a message to the queue and then aborts, the queue will reject the message.

1. Delivery and Playback

When a nontransactional client calls a queued service, client-side failures after the call will not roll back posting the message to the queue, and the queued call will be dispatched to the service. However, a client calling a queued service may call under a transaction, as shown in Figure 1.

Figure 1. Posting to a client-side queue


The client calls are converted to WCF messages and then packaged in an MSMQ message (or messages). If the client’s transaction commits, these MSMQ messages are posted to the queue and persist there. If the client’s transaction aborts, the queue discards these MSMQ messages. In effect, WCF provides clients of a queued service with an auto-cancellation mechanism for their asynchronous, potentially disconnected calls. Normal connected asynchronous calls cannot be combined easily, if at all, with transactions, because once the call is dispatched there is no way to recall it in case the original transaction aborts. Unlike connected asynchronous calls, queued service calls are designed for this very transactional scenario. In addition, the client may interact with multiple queued services in the same transaction. Aborting the client transaction for whatever reason will automatically cancel all calls to those queued services.

1.1. The delivery transaction

Since the client may not be on the same machine as the service, and since the client, the service, or both could be disconnected, MSMQ maintains a client-side queue as well. The client-side queue serves as a “proxy” to the service-side queue. In the case of a remote queued call, the client first posts the message to the client-side queue. When (or if) the client is connected, MSMQ will deliver the queued messages from the client-side queue to the service-side queue, as shown in Figure 2.

Figure 2. The delivery transaction


Since MSMQ is a resource manager, removing the message from the client-side queue will create a transaction (if indeed the queue is transactional). If MSMQ fails to deliver the message to the service-side queue for whatever reason (such as a network fault or service machine crash), the delivery transaction will abort, the message removal from the client-side queue will be rolled back, and the message posting to the service-side queue will also be canceled, resulting in the message being back in the client-side queue. At this point, MSMQ will try again to deliver the message. Thus, while you can configure and control failure handling (as you will see later), excluding fatal errors that can never be resolved, queued services actually enjoy a guaranteed delivery mechanism; if it is technically possible to deliver the message (within the confines of the failure-handling modes), the message will get from the client to the service. In effect, this is WCF’s way of providing reliable messaging for queued services. Of course, there is no direct support for the reliable messaging protocol, as there is with connected calls; this is just the analogous mechanism.

1.2. The playback transaction

When WCF removes a message from the queue for playback to the service, this kick-starts a new transaction (assuming the queue is transactional), as shown in Figure 3.

Figure 3. Playback transaction


The service is usually configured to participate in the playback transaction. If the playback transaction aborts (usually due to service-side exceptions), the message rolls back to the queue, where WCF detects it and dispatches it again to the service. This, in effect, yields an auto-retry mechanism. Consequently, you should keep the service’s processing of the queued call relatively short, or risk aborting the playback transaction. An important observation here is that it is wrong to equate queued calls with lengthy asynchronous calls.

2. Service Transaction Configuration

As just demonstrated, assuming transactional queues, there are actually three transactions involved in every queued call: client, delivery, and playback, as shown in Figure 4.

Figure 4. Queued calls and transactions


From a design perspective, you rarely, if ever, depict the delivery transaction in your design diagrams and you simply take it for granted. In addition, the service will never participate in the client’s transaction, so in effect my four logical transactional modes  (Client, Client/Service, Service, None) do not apply with queued services. Configuring the service contract operation with TransactionFlowOption.Allowed or TransactionFlowOption.NotAllowed leads to the same result—the client transaction is never provided to the service. Not only that, but TransactionFlowOption.Mandatory is disallowed for configuration on a queued contract, and this constraint is verified at the service load time. The real issue is the relation between the playback transaction and the service transactional configuration.

2.1. Participating in the playback transaction

From a WCF perspective, the playback transaction is treated as the incoming transaction to the service. To participate in the playback transaction, the service needs to have the operation behavior configured with TransactionScopeRequired set to true, as shown in Example 1 and graphically in Figure 3.

Example 1. Participating in the playback transaction
[ServiceContract]
interface IMyContract
{
[OperationContract(IsOneWay = true)]
void MyMethod();
}
class MyService : IMyContract
{
[OperationBehavior(TransactionScopeRequired = true)]
public void MyMethod()
{
Transaction transaction = Transaction.Current;
Debug.Assert(transaction.TransactionInformation.
DistributedIdentifier != Guid.Empty);
}
}

An interesting point made in Example 1 is that with both MSMQ 3.0 and MSMQ 4.0, every transaction always uses the DTC for transaction management, even in the case of a single service and a single playback. This might change in the next release of WCF and the .NET Framework.

2.2. Ignoring the playback transaction

If the service is configured for not having any transactions (like the service shown in Example 2), WCF will still use a transaction to read the message from the queue, except that transaction will always commit (barring an unforeseen failure in MSMQ itself). Exceptions and failures at the service itself will not abort the playback transaction.

Example 2. Ignoring the playback transaction
[ServiceContract]
interface IMyContract
{
[OperationContract(IsOneWay = true)]
void MyMethod();
}
class MyService : IMyContract
{
public void MyMethod()
{
Transaction transaction = Transaction.Current;
Debug.Assert(transaction == null);
}
}

This scenario is depicted graphically in Figure 5.

Figure 5. Ignoring the playback transaction


Services that do not participate in the playback transaction will not have the benefit of automated retries by WCF in the case of a playback failure, and it is possible for the played-back call to fail while the de-queued transaction commits. The main motivation for configuring queued services this way is to accommodate lengthy processing. If the service does not participate in the playback transaction, the call can take any amount of time to complete.

2.3. Using a separate transaction

You can also write a service so that it manually requires a new transaction, as shown in Example 3.

Example 3. Using a new transaction
class MyService : IMyContract
{
public void MyMethod()
{
using(TransactionScope scope = new TransactionScope())
{
...
scope.Complete();
}
}
}

This scenario is depicted in Figure 6.

Figure 6. Using a new transaction


When the service uses its own new transaction for each message, it should also prevent participating in the playback transaction (by defaulting to the TransactionScopeRequired value of false) so as not to affect the playback transaction in any way. Again, this negates the benefit of the auto-retry mechanism. However, having a new transaction separate from the playback transaction gives the service the opportunity to perform its own transactional work. You would typically configure a service to use its own transaction when the queued operation being called is nice to have and should be performed under the protection of a transaction, yet does not need to be retried in case of a failure.

3. Nontransactional Queues

The MSMQ queues described so far were both durable and transactional. The messages persisted to the disk, and posting a message to and reading it from the queue was transactional. However, MSMQ also supports nontransactional queues. Such queues can be durable and persist on the disk or can be volatile (stored in memory). If the queue is volatile, the messages in the queue will not persist across a machine shutdown or a machine crash or just recycling of the MSMQ service.

When you create a queue (either using the MSMQ administration tool or programmatically), you can configure it to be transactional or not, and that selection is fixed for the life of the queue. Nontransactional queues do not offer any of the benefits of transactional messaging systems, such as auto-cancellation, guaranteed delivery, and auto-retries. When using a nontransactional queue, if the client transaction aborts, the message or messages will stay in the queue and be delivered to the service. If the playback transaction aborts, the messages will be lost.

As inadvisable as it is, WCF can work with nontransactional queues. MsmqBindingBase (the base class of NetMsmqBinding) offers the two Boolean properties Durable and ExactlyOnce, and these properties default to true:

public abstract class MsmqBindingBase : Binding,...
{
public bool Durable
{get;set;}
public bool ExactlyOnce
{get;set;}
//More members
}
public class NetMsmqBinding : MsmqBindingBase
{...}

To work with a nontransactional queue, the ExactlyOnce property must be set to false. This will enable you to work both with volatile and durable queues. However, because of the lack of guaranteed delivery, when using a volatile queue WCF requires that you set the ExactlyOnce property of the binding to false; otherwise, WCF will throw an InvalidOperationException at the service load time. Consequently, here is a consistent configuration for a volatile nontransactional queue:

<netMsmqBinding>
<binding name = "VolatileQueue"
durable = "false"
exactlyOnce = "false"
/>
</netMsmqBinding>

Other  
 
Most View
Repair Your Smartphone And Tablet (Part 2)
SQL Injection : Platform-Level Defenses - Using Runtime Protection (part 2) - Intercepting Filters
Programming .NET Components : Working with Threads (part 1)
Windows Server 2008 R2 Powershell Cmdlets (part 2) - AppLocker cmdlets
Microsoft Dynamics AX 2009 : Browsing for folders
Sony Nex-5R – A Camera With Improved Performance And Focusing (Part 3)
ASRock FM2A85X Extreme6 Socket FM2 Mainboard Review (Part 6)
Belkin Screencast AV4 - Great Way To Create An Elegant Entertainment Environment
Windows 7 : Working with the Multi-Touch User Interface (part 3) - Adding Multi-Touch Interface Functionality
Panasonic Lumix GH3 – The Fastest Touchscreen-Camera (Part 1)
Top 10
Sharepoint 2013 : Farm Management - Disable a Timer Job,Start a Timer Job, Set the Schedule for a Timer Job
Sharepoint 2013 : Farm Management - Display Available Timer Jobs on the Farm, Get a Specific Timer Job, Enable a Timer Job
Sharepoint 2013 : Farm Management - Review Workflow Configuration Settings,Modify Workflow Configuration Settings
Sharepoint 2013 : Farm Management - Review SharePoint Designer Settings, Configure SharePoint Designer Settings
Sharepoint 2013 : Farm Management - Remove a Managed Path, Merge Log Files, End the Current Log File
SQL Server 2012 : Policy Based Management - Evaluating Policies
SQL Server 2012 : Defining Policies (part 3) - Creating Policies
SQL Server 2012 : Defining Policies (part 2) - Conditions
SQL Server 2012 : Defining Policies (part 1) - Management Facets
Microsoft Exchange Server 2010 : Configuring Anti-Spam and Message Filtering Options (part 4) - Preventing Internal Servers from Being Filtered