Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is NServiceBus (AsA_Server) without DTC possible?

I am using NServiceBus for the first time and have a small, simple application where a user submits a form, the form fields are then sent to the queue, and the handler collects this data and writes it to the database using linq-to-sql.

Any changes within Component Services is a complete no-no as far as the DBA is concerned, so I'm now looking for an alternative to DTC (which is not enabled on the DB server), but using AsA_Server so that messages do not get purged.

I have tried removing AsA_Server after IConfigureThisEndpoint and specifying the configuration myself, but this doesn't seem to work (the console appears, page loads but nothing happens, it doesn't even stop at breakpoints.) AsA_Client does work, but as I understand it the messages will be purged at startup which I need to avoid.

Any suggestions?

Thanks,

OMK

EDIT: This has now been resolved by using wrapping the call to the database in a suppress transaction scope, which allows the database work to be done with no ambient transaction to enlist in:

using (TransactionScope sc = new TransactionScope(TransactionScopeOption.Suppress)) 
{ 
     // code here 
     sc.Complete(); 
} 
like image 920
Matt Avatar asked Jul 19 '11 13:07

Matt


4 Answers

When you use AsA_Server, you are specifying you want durable queues and you will need to configure transactional queues.

With a transactional send/receive MSMQ requires you to send, transmit, receive, and process as part of one transaction. However, actually all these stages take place in their own transactions.

For example, the send transaction is complete when the sender sends a message onto their local MSMQ subsystem (even if the queue address is remote, the sender still sends to a local queue which acts as a kind of proxy to the remote queue).

The transmit transaction is complete when the MSMQ subsystem on the senders machine successfully transmits the message to the MSMQ subsystem on the receivers machine.

Even though this may all happen on one machine, I am guessing that your Handle() method is writing to a database on a different machine.

The problem here is that for the receive operation to complete satisfactorily from a transaction perspective, your call to the database must be successful. Only then will the message be de-queued from your input queue. This prevents any chance that the message is lost during processing failure.

However, in order to enforce that across the network you need to involve DTC to coordinate the distributed transaction to the database.

Bottom line, if you want durable queues in a distributed environment then you will need to use MSDTC.

Hope this helps.

like image 183
tom redfern Avatar answered Oct 01 '22 09:10

tom redfern


There is an alternative. In your connection string you can add the option to not enlist in a distributed transaction and this will have your DB connection ignored in the DTC.

Of course, if this is set in the config then all database transactions for the application are ignored by the DTC rather than just a specific one.

Example:

<add key="DatabaseConnectionString" value="Data Source=SERVERNAME;Initial Catalog=DBNAME;Integrated Security=True;Enlist=False"/>
like image 43
Fellmeister Avatar answered Oct 01 '22 09:10

Fellmeister


With NServiceBus 4.0 you can now do the following, which finally worked for me:

 Configure.Transactions.Advanced(t =>
                {
                    t.DisableDistributedTransactions();
                    t.DoNotWrapHandlersExecutionInATransactionScope();
                });
like image 42
Björn Holdt Avatar answered Oct 01 '22 07:10

Björn Holdt


When you use the As (AsA_Client, AsA_Server) interfaces, the configuration is applied after Init() so all the settings that you make there regarding MsmqTransport and UnicastBus are overriden.

It's possible to override those settings using IWantTheConfiguration in a IHandleProfile implementation. You get the Configuration after the default roles are applied but before the bus is started.

This way you can change the default profile settings and tailor them to your needs: deactivate transactions, enable impersonation...

Example:

public class DeactivateTransactions : IHandleProfile<Lite>, IWantTheEndpointConfig
{
    private IConfigureThisEndpoint configure;

    public IConfigureThisEndpoint Config
    {
        get { return configure; }
        set
        {
            this.configure = value;

            Configure.Instance.MsmqTransport()
                .PurgeOnStartup(false)
                .IsTransactional(false); // Or other changes
        }
    }

    public void ProfileActivated()
    {
    }
}
like image 32
Marc Climent Avatar answered Oct 01 '22 09:10

Marc Climent