Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Async Consumer and use of TransactionScope

Tags:

c#

ibm-mq

I'm using the IBM.XMS lib to talk to WebSphereMQ.

When receiving messages using the synchronous method, eg:

using (var scope = new TransactionScope(TransactionScopeOption.Required, transactionOptions))
{
       message = consumer.Receive(1000);

       if (message != null)
       {
            //Do work here
            scope.Complete();
       }
}

But if I want to use the asynchronous method:

consumer.MessageListener = delegate(IMessage msg)
{
    //Do work here
    //But where do I put TransactionScope?
};

I can't work out how to wrap the MessageListener callback within a TransactionScope.

Does anyone know how to do this?

like image 515
John Simons Avatar asked Apr 04 '13 03:04

John Simons


2 Answers

A message listener a.k.a Asynchronous Consumer can't be used in a TransactionScopeas the message listener runs on a different thread than the thread that created the TransactionScope. You can only use the synchronous Receive/Send inside a TransactionScope.

This link says "The XA transactions are not supported in asynchronous consumers."

like image 131
Shashi Avatar answered Oct 13 '22 19:10

Shashi


It may well be worth your while investigating using DependentClone to create a DependentTransaction.

"A dependent transaction is a transaction whose outcome depends on the outcome of the transaction from which it was cloned."

"The DependentTransaction is a clone of a Transaction object created using the DependentClone method. Its sole purpose is to allow the application to come to rest and guarantee that the transaction cannot commit while work is still being performed on the transaction (for example, on a worker thread)."

Edit: Just spotted this in the related SO questions list: related question and answer see the msdn link they supplied: well worth a read Managing Concurrency with DependentTransaction

Taken from the MSDN link above (for brevity):

public class WorkerThread
{
    public void DoWork(DependentTransaction dependentTransaction)
    {
        Thread thread = new Thread(ThreadMethod);
        thread.Start(dependentTransaction); 
    }

    public void ThreadMethod(object transaction) 
    { 
        DependentTransaction dependentTransaction = transaction as DependentTransaction;
        Debug.Assert(dependentTransaction != null);

        try
        {
            using(TransactionScope ts = new TransactionScope(dependentTransaction))
            {
                /* Perform transactional work here */ 
                ts.Complete();
            }
        }
        finally
        {
            dependentTransaction.Complete(); 
            dependentTransaction.Dispose(); 
        }
    }

//Client code 
using(TransactionScope scope = new TransactionScope())
{
    Transaction currentTransaction = Transaction.Current;
    DependentTransaction dependentTransaction;    
    dependentTransaction = currentTransaction.DependentClone(DependentCloneOption.BlockCommitUntilComplete);
    WorkerThread workerThread = new WorkerThread();
    workerThread.DoWork(dependentTransaction);

    /* Do some transactional work here, then: */
    scope.Complete();
}
like image 32
Paul Zahra Avatar answered Oct 13 '22 19:10

Paul Zahra