0

I've read blog post from John Thiriet about making "Fire and forget" method. I did implement his extension method although I get en error when using it.

Sample code below:

    public async Task<ActionResult> Index()
    {
      /* 
        a lot of work here 
        some sync services called, some awaits to async services
       */

        // here I wanted to call logging service using "fire and forget",
        // because I don't really care about it, 
        // and I don't need to wait for it to show the page for user
        _logService.LogAsync(obj).FireAndForgetSafeAsync();
        return RedirectToAction("Summary");
    }

The method from this blog post is as follow:

public static class TaskUtilities
{
#pragma warning disable RECS0165 // Asynchronous methods should return a Task instead of void
    public static async void FireAndForgetSafeAsync(this Task task, IErrorHandler handler = null)
#pragma warning restore RECS0165 // Asynchronous methods should return a Task instead of void
    {
        try
        {
            await task;
        }
        catch (Exception ex)
        {
            handler?.HandleError(ex);
        }
    }
}

And the code is making An asynchronous module or handler completed while an asynchronous operation was still pending exception. I know it is because of the logging code, but I am not sure why. When I make try catch inside Index with await LogAsync it works fine (also doing "slow" debugging works as well). How can be this code handled to work properly? Can we make such extension method to make some operation "fire and forget" in controller using awaits for other methods? Can someone explain to me what's really wrong and why it was not working? SImilar threads did not help me explain my problem. Thank you.

trinny
  • 222
  • 1
  • 5
  • 22
  • Does this address your issue? https://stackoverflow.com/a/28806198/1149773. You need to use `HostingEnvironment.QueueBackgroundWorkItem` – Douglas Jan 11 '19 at 18:33

1 Answers1

1

If your fire and forget logging code uses any of the pipeline's context (for example, if you are logging the caller's querystring) you MUST await the logging call, somewhere, before the HTTP request completes. Otherwise the context may disappear before it is logged when ASP.NET tears down the pipeline it created for the request. That's why ASP.NET gives you get that error, to protect you from yourself.

If your fire and forget logging code does NOT use any of the pipeline's context (for example, it only accesses data provided to it in arguments) then you can allow it to run after the pipeline is complete by using QueueBackgroundWorkItem.

See also this answer.

John Wu
  • 50,556
  • 8
  • 44
  • 80