Share via

How does the COM+ transaction timeout work?

Anonymous
2016-10-25T11:52:53+00:00

I do not understand, how the transaction timeout works in COM+. I have the class ClassComPlus which inherits from ServicedComponent, has transaction timeout attribute set to 1 second, and has a method SubSleep, that sleeps 3 seconds. I expect, the client which calls the method SubSleep to get an exception, because the transaction timeout has elapsed, but I do not get such an exception, the method completes without an exception. 

Here is the code in VB.NET:

  1. Project Test1BO.vbproj as Class Library signed with a strong key, having the two files:

  1.1 AssemblyInfo.vb:

    Imports System.EnterpriseServices 

    Imports System.Reflection 

    Imports System.Runtime.InteropServices 

    <Assembly: ApplicationActivation(ActivationOption.Server)>  

    <Assembly: ApplicationAccessControl(CType(AccessChecksLevelOption.Application, Boolean))>  

    <Assembly: Guid("799facfd-af56-4496-bc18-618e2522e5f7")>  

    <Assembly: AssemblyVersion("1.0.0.0")>  

    <Assembly: AssemblyFileVersion("1.0.0.0")>

  1.2 ClassComPlus.vb

    Imports System.EnterpriseServices

    <Transaction(TransactionOption.Required, isolation:=TransactionIsolationLevel.ReadCommitted, timeout:=1), _

     EventTrackingEnabled(True), _

     JustInTimeActivation(True)> _

    Public Class ClassComPlus

        Inherits ServicedComponent

        Public Sub SubSleep()

            Try

                Threading.Thread.Sleep(3000)

                ContextUtil.SetComplete()

            Catch

                ContextUtil.SetAbort()

                Throw

            End Try

        End Sub

    End Class

Test1BO must be registered in COM+ for example with the following RegisterComPlus.bat file in the folder where the dll is created:

    set regsvcs=C:\Windows\Microsoft.NET\Framework\v4.0.30319\regsvcs

    set topdir=%~dp0

    set dllname=Test1BO

    %regsvcs% /u "%topdir%%dllname%.dll"

    %regsvcs% "%topdir%%dllname%.dll"

    pause

  1. Project Test1CA.vbproj as Console Application with reference to Test1BO.dll has just Module1.vb:

    Module Module1

        Sub Main()

            Dim obj = New Test1BO.ClassComPlus

            Try

                obj.SubSleep()

                Console.WriteLine("SubSleep finished normally (unexpected)")

            Catch ex As Exception

                Console.WriteLine("SubSleep threw exception (expected)")

                Console.WriteLine(ex.ToString)

            Finally

                obj.Dispose()

            End Try

            Console.ReadKey()

        End Sub

    End Module

I would expect, that because the transaction timeout is 1 second, but the sleep time is 3 seconds, that the statement obj.SubSleep would throw an exception. Instead, obj.SubSleep finishes normally. 

  1. What am I doing wrong? 
  2. Did I wrongly understood the transaction timeout?
Windows for home | Previous Windows versions | Apps

Locked Question. This question was migrated from the Microsoft Support Community. You can vote on whether it's helpful, but you can't add comments or replies or follow the question.

0 comments No comments

2 answers

Sort by: Most helpful
  1. Anonymous
    2016-12-19T06:27:05+00:00

    With the help of Microsoft, I finally understood how the COM+ transaction timeout works. The COM+ transaction timeout, is a timeout on the transaction, not on the method call. The method will execute, as long as it has to execute. The moment the first transaction is enlisted, the transaction timeout starts to work. If the transaction takes more time than the specified timeout, the transaction is marked for abortion, but is not canceled, it continues to run. When the COM+ method calls SetComplete, only then an exception is thrown. The timeout exception is the following: System.Runtime.InteropServices.ComException: {"The root transaction wanted to commit, but transaction aborted (Exception from HRESULT: 0x8004E002)"}. A transaction is enlisted as soon as a connection is opened to the database or as soon as something is written to a message queue.

    Suppose the transaction timeout is 10 seconds. Let us consider the following 3 cases:

    1. The COM+ method immediately enlists a transaction that takes 11 seconds. 

      In this case the timeout exception is thrown after 11 seconds, because the transaction took longer than the timeout.

    1. The COM+ method sleeps for 6 seconds (or does some calculations) and then enlists a transaction that takes 5 seconds.

      In this case the method completes without an error, although the total execution time is also 11 seconds. 

    1. The COM+ method immediately enlists a transaction that takes 5 seconds, and then sleeps for 6 seconds.

    In this case the timeout exception is thrown after 11 seconds, because the time between the enlistment of the transaction and the SetΨomplete call is 11 seconds, which is more than the timeout.

    In summary: If the time between the first enlistment of the transaction and the SetComplete call is more than the transaction timeout, the timeout exception is thrown. However, the COM+ method always runs, for as long as it has to run, irrespective to the transaction timeout.

    To test the above cases, here is the code in VB.NET:

    1. Project Test1BO.vbproj as Class Library signed with a strong key, having the two files:

      1.1 AssemblyInfo.vb:

        Imports System.EnterpriseServices 

        Imports System.Reflection 

        Imports System.Runtime.InteropServices 

        <Assembly: ApplicationActivation(ActivationOption.Server)>  

        <Assembly: ApplicationAccessControl(CType(AccessChecksLevelOption.Application, Boolean))>  

        <Assembly: Guid("799facfd-af56-4496-bc18-618e2522e5f7")>  

        <Assembly: AssemblyVersion("1.0.0.0")>  

        <Assembly: AssemblyFileVersion("1.0.0.0")>

      1.2 ClassComPlus.vb

    Imports System.EnterpriseServices

    Imports System.Data.SqlClient

    Imports System.Transactions

    <Transaction(TransactionOption.Required, isolation:=TransactionIsolationLevel.Serializable, timeout:=10), _

     EventTrackingEnabled(True), _

     JustInTimeActivation(True)>

    Public Class ClassComPlus

        Inherits ServicedComponent

        Public Function DbExecuteNonQuery(

            connectionString As String, cmdText As String,

            sleepSecondsBefore As Integer, sleepSecondsAfter As Integer) As Integer

            Try

                Threading.Thread.Sleep(sleepSecondsBefore * 1000)

                Dim result = 0

                Using cn = New SqlConnection(connectionString)

                    cn.Open()

                    Dim cmd = New SqlCommand(cmdText, cn)

                    result = cmd.ExecuteNonQuery()

                End Using

                Threading.Thread.Sleep(sleepSecondsAfter * 1000)

                ContextUtil.SetComplete()

                Return result

            Catch

                ContextUtil.SetAbort()

                Throw

            End Try

        End Function

    Test1BO must be registered in COM+ for example with the following RegisterComPlus.bat file in the folder where the dll 

    is created:

        set regsvcs=C:\Windows\Microsoft.NET\Framework\v4.0.30319\regsvcs

        set topdir=%~dp0

        set dllname=Test1BO

        %regsvcs% /u "%topdir%%dllname%.dll"

        %regsvcs% "%topdir%%dllname%.dll"

        pause

    1. Project Test1CA.vbproj as Console Application with reference to Test1BO.dll has just Module1.vb:

        Module Module1

        Private Sub MyTrace(s As String)

            Console.WriteLine(String.Format("{0} {1}", Now.ToString("yyyy-MM-dd HH:mm:ss"), s))

        End Sub

        Private Sub TestDbExecNonQuery()

            Dim obj = New Test1BO.ClassComPlus

            Dim connectionString = ConfigurationManager.ConnectionStrings("DB1").ConnectionString

            Dim cmdText = "WAITFOR DELAY '00:00:011'"

            Try

                MyTrace("TestDbExecNonQuery begin " & cmdText & ", 0, 0")

                obj.DbExecuteNonQuery(connectionString, cmdText, 0, 0)

                MyTrace("TestDbExecNonQuery end")

            Catch ex As Exception

                MyTrace("TestDbExecNonQuery exception")

                MyTrace(ex.Message)

            End Try

            cmdText = "WAITFOR DELAY '00:00:05'"

            Try

                MyTrace("TestDbExecNonQuery begin " & cmdText & ", 6, 0")

                obj.DbExecuteNonQuery(connectionString, cmdText, 6, 0)

                MyTrace("TestDbExecNonQuery end")

            Catch ex As Exception

                MyTrace("TestDbExecNonQuery exception")

                MyTrace(ex.Message)

            End Try

            Try

                MyTrace("TestDbExecNonQuery begin " & cmdText & ", 0, 6")

                obj.DbExecuteNonQuery(connectionString, cmdText, 0, 6)

                MyTrace("TestDbExecNonQuery end")

            Catch ex As Exception

                MyTrace("TestDbExecNonQuery exception")

                MyTrace(ex.Message)

            End Try

            obj.Dispose()

        End Sub

        Sub Main()

            TestDbExecNonQuery()

            Console.WriteLine("Press any key to close")

            Console.ReadKey()

        End Sub

        End Module

    Running the above, the following output is expected:

    2016-12-09 16:47:17 TestDbExecNonQuery begin WAITFOR DELAY '00:00:011', 0, 0

    2016-12-09 16:47:29 TestDbExecNonQuery exception

    2016-12-09 16:47:29 The root transaction wanted to commit, but transaction abort

    ed (Exception from HRESULT: 0x8004E002)

    2016-12-09 16:47:29 TestDbExecNonQuery begin WAITFOR DELAY '00:00:05', 6, 0

    2016-12-09 16:47:40 TestDbExecNonQuery end

    2016-12-09 16:47:40 TestDbExecNonQuery begin WAITFOR DELAY '00:00:05', 0, 6

    2016-12-09 16:47:51 TestDbExecNonQuery exception

    2016-12-09 16:47:51 The root transaction wanted to commit, but transaction abort

    ed (Exception from HRESULT: 0x8004E002)

    Press any key to close

    Microsoft assured me that it still considers COM+ an important product, and will continue to provide it for many years to come, and recommends the use of COM+ especially in intranet installations, where it is even faster than WCF.

    Was this answer helpful?

    1 person found this answer helpful.
    0 comments No comments
  2. Anonymous
    2016-12-18T22:15:31+00:00

    Hi,

    Regarding your concern, we suggest that you post your query on our Technet forums page for better assistance.

    Regards.

    Was this answer helpful?

    0 comments No comments