Programming WCF Services : Queued Services - Transactions

4/28/2011 4:20:39 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.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
interface IMyContract
[OperationContract(IsOneWay = true)]
void MyMethod();
class MyService : IMyContract
[OperationBehavior(TransactionScopeRequired = true)]
public void MyMethod()
Transaction transaction = Transaction.Current;
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
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())

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
public bool ExactlyOnce
//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:

<binding name = "VolatileQueue"
durable = "false"
exactlyOnce = "false"

  •  Exchange Server 2010 : Implementing Client Access and Hub Transport Servers - Test Cmdlets for CAS and Hub Transport Servers
  •  Exchange Server 2010 : Implementing Client Access and Hub Transport Servers - Installing the Hub Transport Server
  •  Exchange Server 2010 : Implementing Client Access and Hub Transport Servers - Transport Pipeline
  •  Exchange Server 2010 : Implementing Client Access and Hub Transport Servers - Understanding the Hub Transport Server
  •  Implementing Client Access and Hub Transport Servers : Installing the Client Access Server
  •  Implementing Client Access and Hub Transport Servers : Understanding the Client Access Server (part 2)
  •  Implementing Client Access and Hub Transport Servers : Understanding the Client Access Server (part 1)
  •  SharePoint 2010 : Implementing and Managing In Place Records
  •  Understanding Exchange Policy Enforcement Security : Creating Messaging Records Management Policies
  •  Understanding Exchange Policy Enforcement Security : Implementing Transport Agent Policies on the Edge
  •  Safeguarding Confidential Data in SharePoint 2010 : Using Active Directory Rights Management Services (AD RMS) for SharePoint Document Libraries
  •  Safeguarding Confidential Data in SharePoint 2010 : Enabling TDE for SharePoint Content Databases
  •  Safeguarding Confidential Data in SharePoint 2010 : Using SQL Transparent Data Encryption (TDE)
  •  Safeguarding Confidential Data in SharePoint 2010 : Enabling SQL Database Mirroring
  •  Safeguarding Confidential Data in SharePoint 2010 : Outlining Database Mirroring Requirements
  •  Remote Administration of Exchange Server 2010 Servers : RDP with Exchange Server 2010 (part 2)
  •  Remote Administration of Exchange Server 2010 Servers : RDP with Exchange Server 2010 (part 1) - Planning and Using Remote Desktop for Administration
  •  Remote Administration of Exchange Server 2010 Servers : Using the ECP Remotely
  •  Safeguarding Confidential Data in SharePoint 2010 : Examining Supported Topologies
  •  SharePoint 2010 : SQL Server Database Mirroring for SharePoint Farms
    Top 10
    Nikon 1 J2 With Stylish Design And Dependable Image And Video Quality
    Canon Powershot D20 - Super-Durable Waterproof Camera
    Fujifilm Finepix F800EXR – Another Excellent EXR
    Sony NEX-6 – The Best Compact Camera
    Teufel Cubycon 2 – An Excellent All-In-One For Films
    Dell S2740L - A Beautifully Crafted 27-inch IPS Monitor
    Philips 55PFL6007T With Fantastic Picture Quality
    Philips Gioco 278G4 – An Excellent 27-inch Screen
    Sony VPL-HW50ES – Sony’s Best Home Cinema Projector
    Windows Vista : Installing and Running Applications - Launching Applications
    Most View
    Bamboo Splash - Powerful Specs And Friendly Interface
    Powered By Windows (Part 2) - Toshiba Satellite U840 Series, Philips E248C3 MODA Lightframe Monitor & HP Envy Spectre 14
    MSI X79A-GD65 8D - Power without the Cost
    Canon EOS M With Wonderful Touchscreen Interface (Part 1)
    Windows Server 2003 : Building an Active Directory Structure (part 1) - The First Domain
    Personalize Your iPhone Case
    Speed ​​up browsing with a faster DNS
    Using and Configuring Public Folder Sharing
    Extending the Real-Time Communications Functionality of Exchange Server 2007 : Installing OCS 2007 (part 1)
    Google, privacy & you (Part 1)
    iPhone Application Development : Making Multivalue Choices with Pickers - Understanding Pickers
    Microsoft Surface With Windows RT - Truly A Unique Tablet
    Network Configuration & Troubleshooting (Part 1)
    Panasonic Lumix GH3 – The Fastest Touchscreen-Camera (Part 2)
    Programming Microsoft SQL Server 2005 : FOR XML Commands (part 3) - OPENXML Enhancements in SQL Server 2005
    Exchange Server 2010 : Track Exchange Performance (part 2) - Test the Performance Limitations in a Lab
    Extra Network Hardware Round-Up (Part 2) - NAS Drives, Media Center Extenders & Games Consoles
    Windows Server 2003 : Planning a Host Name Resolution Strategy - Understanding Name Resolution Requirements
    Google’s Data Liberation Front (Part 2)
    Datacolor SpyderLensCal (Part 1)