DisableDistributedTransactions usage

837 views
Skip to first unread message

Maciek Sobocinski

unread,
Mar 29, 2014, 3:22:46 PM3/29/14
to particula...@googlegroups.com
Hi,

I'm trying to get my head around these two settings and what exactly happens when I turn them off/on: DisableDistributedTransactions and DoNotWrapHandlersExecutionInATransactionScope. 

What we are trying to achieve is to be able to begin the transaction scope within the handler lazily (upon the first bus.send or first db update/insert) but yet still have both the msmq work and db work be within the same transaction and rollback together in case of failure. Is this a valid idea/is there benefit to being lazy (the though behind it is better performance) or should we just let nsb handle it?

Am I correct in understanding these scenarios:

1) DisableDistributedTransactions = off, DoNotWrapHandlersExecutionInATransactionScope = off . The entire handler will be wrapped in an outer transaction scope. Any Bus.Sends will not be immediate and will wait till the outer transaction scope completes. In case of a rollback of the outer transaction scope all the Bus.Sends will be rolled back as well as any database work enlisted in the transaction scope will roll back.

2) DisableDistributedTransactions = on, DoNotWrapHandlersExecutionInATransactionScope = off. The entire handler will be wrapped in an outer transaction scope. Any Bus.Sends will be immediate and will not participate in the outer transaction scope. In the case of a rollback of the outer transaction scope the bus.sends will not roll back but any database work in the handler will roll back.

3) DisableDistributedTransactions = off, DoNotWrapHandlersExecutionInATransactionScope = on. The handler will not be wrapped in an outer transaction scope. I will explicitly have to start a transaction scope and any bus.sends will not be immediate (they completed upon outer transaction scope complete) and database work done within the manually started one will rollback together. Anything outside of my manually created transaction scope will not rollback.

4) DisableDistributedTransactions = on, DoNotWrapHandlersExecutionInATransactionScope = on. The handler will not be wrapped in an outer transaction scope. Each bus.send will be within its own transaction and if a transaction scope is created manually by me those bus sends will not enlist in it will execute immediately and will not roll back if the outer transaction scope rolls back. Any db work done within the manual transaction scope will roll back.


Thanks!

Helpful information to include
Product name: NServiceBus
Version: 3.3 (upgrading to 4 within the next 1-2 months)
Stacktrace:
Description:

indu.alagarsamy

unread,
Apr 2, 2014, 1:01:01 AM4/2/14
to particula...@googlegroups.com
Hi,
 
The best thing to do would be to let NServiceBus handle it for you. What's the reason you are looking to do this?  Is there a current problem with the performance?  
As far as I know, a transaction scope needs to exist first, irrespective of what happens during the operation, if you want the rollback behavior. And these settings are at the endpoint level. So, I don't think that lazy is valid.
Can you explain your business use case scenario that you are hoping to achieve?

As to your understanding of these settings, I think they are correct. But I'll run it by Andreas to confirm.
For the last case to turn off transactions completely, I think that you'd also need to Configure.Transactions.Disable();

Thank you for raising this. Currently our documentation is thin around this area. 
We have opened an issue to address this: (https://github.com/Particular/docs.particular.net/issues/243)
I'll post back here, as soon as we have the created the documentation for these settings.

Thanks,
Indu Alagarsamy
Particular Software

Maciek Sobocinski

unread,
Apr 2, 2014, 11:39:18 AM4/2/14
to particula...@googlegroups.com

Today we have an NServiceBus host that will invoke a WCF service (legacy) to do some work, and the transaction scope does not span the WCF service call. If the WCF service fails, NServiceBus will fail and go through its normal retry process that we’ve configured. If the WCF service succeeds but the NServiceBus host fails (maybe due to timeout or service interrupt), we’ve had to implement our server-side logic to be idempotent. Our team is looking to start migrating code out of the WCF service and into the NServiceBus handler, but the default transaction scope in NServiceBus can be problematic for scenarios where we aggressively control the transaction lifetime:


1.       foreach(file in directory) => { using TransactionScope(); Bus.Send(new command { file }); MoveFile(file); TransactionScope.Complete(“start processing file in another thread”); }

2.       DoX(); IdempotentDataAccess(); TransactionScope.Complete(“avoid long running db transactions”); DoTimeConsumingWorkY();


With each of these scenarios running in a separate process (WCF service), we can granularly control transaction boundaries for these edge cases without fear of losing messages on the NServiceBus side. If we migrate our business logic to run within the NServiceBus project, and we want to keep the same transaction model, I’m assuming we need to start playing with some of these configuration options. One of my goals with this thread is to understand if the durability of the messages (MSMQ transport) will be impacted by using these settings (e.g. what happens to the message if we are running with disabled transactionscope option, and the NServiceBus host shuts off mid-process… does it stay in queue? is the message lost?).

By the way, for #2, I realize we can move “DoTimeConsumingWorkY()” to its own queued message and then we don’t need to complete the transactionscope ourselves. For the sake of deepening my understanding of NServiceBus transaction management + MSMQ, I’d like to shelve any refactor suggestions and instead understand consequences of using the transaction-related configuration options.

andreas.ohlund

unread,
Apr 4, 2014, 3:40:47 PM4/4/14
to particula...@googlegroups.com
>One of my goals with this thread is to understand if the durability of the messages (MSMQ transport) will be impacted by using these settings (e.g. what happens to the message if we are running with disabled transactionscope option, and the NServiceBus host shuts off mid-process… does it stay in queue? is the message lost?).

The only time you can risk loosing messages are when you turn transactions of , Configure.Transactions.Disable(). This means that we pull the message off the queue without either a DTC-aware TX or a native MSMQ tx. This means that any exception in the handler pipeline will result in message loss.

All the other options will result in the message being rolled back to the queue and retried. For this scenario disabling distributed transactions means that any database work done on the pipeline might not roll back depending on where the ex occurs.

Outgoing messages that results from the message being processed usually rolls back regardless if you use DTC or not if the queuing system supports cross queue transactions. Most queuing systems supports this except RabbitMQ. The way we try to mitigate this is to use a volatile transaction manager to delay talking to rabbit until the entire pipeline commits. This means that no messages will be sent/published unless data is committed to your DB.

Hope this helps!

Maciek Sobocinski

unread,
Apr 7, 2014, 10:04:35 PM4/7/14
to particula...@googlegroups.com

Thank you - this is helpful.

Just to make sure I'm correct and close this thread out:

With 'DisableDistributedTransactions' on nservicebus will use the native msmq tx but the code in my handler will still be wrapped in a transaction scope required (in which the native msmq transaction will not participate). If I then turn on 'DoNotWrapHandlersExecutionInATransactionScope' the code in my handler will be wrapped in a transaction scope suppress at which point I can have granular control over transactions within my code. With either setting or both turned on when an exception/shutdown occurs any messages sent within in will still roll back and the handler will retry. With either setting or both turned on none of my code will participate in the same transaction as msmq and in the case where an exception/shutdown occurs within the nservicebus pipeline AFTER the transaction that is initiated from my code commits the handler will rollback but the transaction initiated by me will not - I will need de-duplication logic to cover this scenario.

Andreas Öhlund

unread,
Apr 7, 2014, 11:01:03 PM4/7/14
to particula...@googlegroups.com
That is correct!

Sent from my iPhone
--
You received this message because you are subscribed to the Google Groups "Particular Software" group.
To unsubscribe from this group and stop receiving emails from it, send an email to particularsoftw...@googlegroups.com.
To post to this group, send email to particula...@googlegroups.com.
Visit this group at http://groups.google.com/group/particularsoftware.
To view this discussion on the web visit https://groups.google.com/d/msgid/particularsoftware/396aa4e9-52b8-49cb-9a3e-5e0e06855e32%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Amit Malina

unread,
Sep 10, 2014, 8:28:27 AM9/10/14
to particula...@googlegroups.com
Hi

In my project there's a  a NServiceBus service who's split xml into small pieces and sending each piece to a second queue (using Send) with in one transaction , 
meaning if one of the small pieces fail i expect nothing to be send.  

I'm using the 4.6.0.0 version of NServiceBus

Here is the configuration i've been using for the sender side . 

public sealed class EndpointConfig : IConfigureThisEndpoint, IWantToRunBeforeConfiguration, AsA_Server    
{
        public void Init()
        {
            Configure.Transactions.Advanced(t =>
            {
                t.WrapHandlersExecutionInATransactionScope();
                t.EnableDistributedTransactions();
            });
        }
    }


As for a result it seems that each message was sent to the target side although  the transaction didn't end normally.
Is that a normal behavior ? 

btw iv'e tried also with the   DisableDistributedTransactions() , DoNotWrapHandlersExecutionInATransactionScope() but got the same behavior. 
 



 





בתאריך יום שבת, 29 במרץ 2014 22:22:46 UTC+3, מאת Maciek Sobocinski:

Amit Malina

unread,
Sep 10, 2014, 8:33:35 AM9/10/14
to particula...@googlegroups.com
I've tried the same technique , but either using   DisableDistributedTransactions  and DoNotWrapHandlersExecutionInATransactionScope    
or WrapHandlersExecutionInATransactionScope  and EnableDistributedTransactions    
i gut the same result  , meaning  a end with in  Handle  sent as a self transaction ( or with out transaction)

Amit.

בתאריך יום שבת, 29 במרץ 2014 22:22:46 UTC+3, מאת Maciek Sobocinski:
Hi,

Andreas Öhlund

unread,
Sep 11, 2014, 12:55:35 PM9/11/14
to particula...@googlegroups.com
The behavior you want is the default in NServiceBus so you should be able to remove the calls to Configure.Transactions.X.

Something else seems to be off, can you share the code in your message handler that does the sends?

--
You received this message because you are subscribed to the Google Groups "Particular Software" group.
To unsubscribe from this group and stop receiving emails from it, send an email to particularsoftw...@googlegroups.com.
To post to this group, send email to particula...@googlegroups.com.
Visit this group at http://groups.google.com/group/particularsoftware.
Reply all
Reply to author
Forward
0 new messages