2

I'm trying to use the Enterprise Library Transient Fault Handling Application Block ("Topaz") to implement a retry policy for asynchronous calls to Azure storage and it's not how to combine the two correctly.

Should I use RetryPolicy.ExecuteAction() or RetryPolicy.ExecuteAsync()?

For example (async execute and async addmessage):

public async Task AddMessageToQueueAsync(string message)
{
     await myRetryPolicy.ExecuteAsync(() => azureQueue.AddMessageAsync(message));
}

or (synchronous execute and async addmessage)

public async Task AddMessageToQueueAsync(string message)
{
     myRetryPolicy.ExecuteAction(async () => 
          await azureQueue.AddMessageAsync(message));
}

or (async execute and synchronous addmessage)

public async Task AddMessageToQueueAsync(string message)
{
     await myRetryPolicy.ExecuteAsync(() => azureQueue.AddMessage(message));
}

I need to await the task one way or the other, as I can't continue until the message has been successfully delivered to the queue.

What I'm finding is that the first example ends up firing off a task that fires off as task that adds a message to the queue -- rendering my await call useless - that is, await ExecuteAsync() returns immediately but the "inner" AddMessageAsync() task is still running. Since this code is being called by an MVC controller action, I end up with an exception that the action completed while there was an asynchronous operation pending.

The other two examples seem to work, but neither one feels right.

Mr. T
  • 3,892
  • 3
  • 29
  • 48
  • Are you sure that's what you're seeing? The `ExecuteAction` method should be the one returning immediately; `ExecuteAsync` should wait for (and retry if necessary) the inner task. – Stephen Cleary Apr 11 '14 at 18:41
  • Well, I *think* that's what I'm seeing - definitely getting the exception at my controller that indicates some task is still executing. But now I'm starting to question whether I should even be using the Transient Fault Handling block at all -- [this link](http://www.nuget.org/packages/EnterpriseLibrary.TransientFaultHandling.WindowsAzure.Storage/) says I should use the built-in retry policies in the Azure Storage Client library instead... – Mr. T Apr 11 '14 at 18:55
  • 1
    Looks like my problem had nothing to with retry policy stuff -- in my controller action, I was (trying) to use `messages.ForEach(async x => await AddMessageToQueueAsync(x.Message));` and it turns out that ForEach doesn't get along well with async / await, as I found in [this Stackoverflow question](http://stackoverflow.com/questions/18667633/how-can-i-use-async-with-foreach) – Mr. T Apr 11 '14 at 19:53
  • 2
    Ah, yes. [As I mentioned](http://stackoverflow.com/a/18668733/263693), one workaround is to use `Select` to project to a sequence of tasks and then `await Task.WhenAll` to (asynchronously) wait for them all to complete. – Stephen Cleary Apr 11 '14 at 21:11

0 Answers0