Using Transactions Through Processes

I am trying to use System.Transactions (TransactionScope) to coordinate a set of processes, each of which works with some databases. Ultimately, all processes must commit or roll back atomically through one parent process. Unfortunately, nothing I've tried so far is working.

My main strategy is TransactionScope in the parent process, saving it to a file and calling the child process that downloads the file, uses the transaction inside its own TransactionScope and returns to the parent.

But this does not work for me. When I return from calling my first child, I sometimes see that the parent transaction is marked as Aborted. Attempting to clone it then throws a TransactionAbortedException.

I also saw exceptions, when the second child tries to deserialize the transaction, I get a TransactionException with the code 0x8004d00e.

I am trying to do what is described in TransactionScope through AppDomains and processes , and http://blogs.microsoft.co.il/blogs/sasha/archive/2010/04/30/propagating-a-transaction-across-appdomains.aspx . Regardless, no luck.

Here are some things I tried without success:

  • Creating a dependent broadcast through DependentClone () in a child process from a loaded transaction
  • Creating a dependent broadcast through DependentClone () in the parent process before saving the transaction to a file
  • Creating a clone () in the parent process before saving the transaction to a file
  • Saving a transaction using serialization
  • TransactionInterop.GetTransactionFromTransmitterPropagationToken()
  • TransactionScope
  • /
  • /
  • CommittableTransaction

:

System.Transactions.TransactionException: . --- > System.Runtime.InteropServices.COMException: ( HRESULT: 0x8004D00E)

( DependentClone()):

System.Transactions.TransactionAbortedException: .   System.Transactions.TransactionStatePromotedAborted.CreateBlockingClone(In ternalTransaction tx)   System.Transactions.DependentTransaction..ctor(IsolationLevel isoLevel, In ternalTransaction internalTransaction, Boolean blocking)   System.Transactions.Transaction.DependentClone(DependentCloneOption cloneO ption)

, ? .

( , ):

        // one variant I have tried is to create a CommittableTransaction
        // and pass that in the scope below

        using (TransactionScope scope = new TransactionScope())
        {
            // optionally, do some parent-level EF work

            // invoke child operations in other processes
            DoChildOperation_OutOfProc(1, Transaction.Current);
            DoChildOperation_OutOfProc(2, Transaction.Current);

            scope.Complete();
        }

        // in the variant where I created a CommittableTransaction,
        // I committed it here

    ...

    private static void DoChildOperation_OutOfProc(int id, Transaction transaction)
    {
        string tranFile = string.Format("ChildTran_{0}.txt", id);
        SaveTransactionToFile(transaction, tranFile);

        Process process = new Process();
        process.StartInfo = new ProcessStartInfo(Process.GetCurrentProcess().MainModule.FileName.Replace(".vshost", string.Empty),
            string.Format("-CHILDID={0} -TRANFILE={1}", id, tranFile));
        process.StartInfo.UseShellExecute = false;
        process.Start();
        process.WaitForExit();
    }

    private static void SaveTransactionToFile(Transaction transaction, string tranFile)
    {
        byte[] transactionBytes =
            TransactionInterop.GetTransmitterPropagationToken(transaction);

        string tranFileContents = Convert.ToBase64String(transactionBytes);

        File.WriteAllText(tranFile, tranFileContents);
    }

    private static Transaction LoadTransactionFromFile(string tranFile)
    {
        string tranFileContents = File.ReadAllText(tranFile);
        File.Delete(tranFile);

        byte[] tranBytes = Convert.FromBase64String(tranFileContents);

        Transaction tran = 
            TransactionInterop.GetTransactionFromTransmitterPropagationToken(tranBytes);
        return tran;
    }

    // the child instance of the app runs this after decoding the arguments
    // from DoChildOperation_OutOfProc() and loading the transaction out of the file

    private static void DoChildOperation(int id, Transaction childTransaction)
    {
        // in one variant, I call 
        // childTransaction.DependentClone(DependentCloneOption.BlockCommitUntilComplete)
        // and then use that inside the TransactionScope

        using (TransactionScope scope = new TransactionScope(childTransaction))
        {
            // do EF work and call SaveChanges()

            scope.Complete();
        }

        // if I created a dependent clone, call Complete() here on it
+2
1

, , , , TransactionScope , . EF, connection.EnlistTransaction() EF SaveChanges() . Rollback(), ( Transaction ). , , .

, ( SQL Server) . , ; . . DependentTransaction Transaction.DependentClone() , , TransactionScope.

, , , TransactionScope, , .

0

All Articles