views:

66

answers:

3

I have an endpoint that has a message handler which does some FTP work. Since the ftp process can take some time, I encapsulated the ftp method within a TransactionScope with TransactionScopeOption.Suppress to prevent the transaction timeout exceptions.

Doing this got rid of the timeout exceptions, however the handler was fired 5 times (retries is set to 5 in my config file)

The files were ftp'd ok, but they were just ftp'd 5 times.

the handler look like it is re-fired after 10 or 11 minutes.

some test code looks as follows:

public void Handle(FtpMessage msg)
{
     using (TransactionScope t = new TransactionScope(TransactionScopeOption.Suppress))
     {
          FtpFile(msg);
     }
}

Any help would be greatly appreciated.

thanks.

A: 

My guess is that by not completing the inner scope you're causing the outer scope, created by NSB, to rollback. This will cause NSB to retry your FtpMessage.

Try to add: t.Complete(); after your call to FtpFile and see if that does it for you.

Edit: After rereading your question I realized that this won't solve your timeout issue. Have you tried to increase the timeout? (10 min is the default maxValue in machine.config so you can't set it to higher without modifying machine.config)

Andreas
@Andreas: Do transactions as handled by NSB have any sort of built-in timeout, and if so, what is the default timeout and can it be modified?
David
@David: Just set the TransactionTimeout when configuring the MsmqTransport (using v2.0) On trunk this has changed to the "TransactionalTransport". Beware that the maximum value is constrained by what's specified in machine.config
Andreas
Thanks for this. I will try amending the machine.config and specifying the TransactioTimeout and see how it goes.
IGoor
A: 

If this truly is an FTP communication that cannot be completed within the transaction timeout, another approach would be to turn this into a Saga.

The Saga would be started by FtpMessage, and in the handler it would start the FTP work asynchronously, whether in another thread, or via another process, or whatever, and store enough information in saga data to be able to look up the progress later.

Then it would request a timeout from the TimeoutManager for however long makes sense. Upon receiving that timeout, it would look up the state in saga data, and check on the FTP work in progress. If it's completed, mark the saga as complete, if not, request another timeout.

Alternatively, you could have a process wrapping the FTP communication that hosts its own Bus but does not have any message handlers of its own. It could receive its FTP information via the command line (including requesting endpoint), do its work, and then send a message back to the requesting endpoint saying it is complete. Then you would not have to wait for a timeout to move on with the process.

David
A: 

I'd recommend configuring that endpoint as non-transactional rather than trying to suppress the transaction. Do that by including .IsTransactional(false) in your initialization code if self-hosting or by implementing IConfigureThisEndpoint, AsA_Client when using the generic host.

Udi Dahan