Fire and forget the async task method sometimes do not call

I have an async method:

public async Task DoSomethingAsync(){ ... await ... await ... .... return await SaveAsync(); } 

In most cases, I call this method:

 await DoSomethingAsync() 

This call works as expected. But somewhere I have to call this method fire and forget:

 public void OtherMethod() { ... DoSomethingAsync(); //fire and forget here } 

In this case, Task DoSomethingAsync() sometimes starts and ends, but sometimes the task is never called (or calls some await inside DoSomethingAsync() , but never completes the last await SaveAsync(); ).

I try to make sure that the task will be called into the fire and forget this code:

 public void OtherMethod() { ... Task.Factory.StartNew(() => { await DoSomethingAsync(); }); //fire and forget again here } 

However, this does not work as an expectation. So my questions are:

  • How to make a DoSomethingAsync() call without await always execute and end? (I don't care what the reboot / AppDomain crashes)

  • If I delete all the async/await code inside DoSomethingAsync() and replace await with .ContinueWith() , then the call to Task DoSomethingAsync() (does not have async in the method declaration) will be called and sure to complete (ignore the AppDomain restart / crash case) , if so, how long is the call (I don’t think I will be happy if Task is called in 10 minutes)?

+6
source share
3 answers

Expectations should work fine, so something else is probably happening here that holds one or more of your expected methods. There are several possibilities:

  • You have a dead end somewhere in one of your methods so that it does not complete and does not block the wait from resuming.
  • All threads in the thread pool are blocked for some reason, preventing pending tasks from starting.
  • You run the async method in a synchronization context, and something holds the context, preventing it from making sent callbacks. Typically, the context will be a UI thread, and usually it’s pretty obvious as it blocks the user interface of the application.

If you can connect using the VS debugger and watch what happens, try pausing and taking a look at the Parallel Stacks view. This should help limit the possibilities of consideration.


As Stephen noted, it is also possible that an Exception occurs when you call it fire and forget it. If you have not already done so, be sure to handle TaskScheduler.UnobservedTaskException to log any events like this. Note that this is called from the finalizer, so the time at which it is called is not deterministic. This can make debugging difficult, as the event may not fire until some event occurs that throws an exception. Therefore, I recommend that you follow Stephen's recommendations and keep the task pending or wait later.

+4
source

You are probably getting an exception somewhere in DoSomethingAsync that you cannot observe because you are ignoring the task. This is exactly the behavior you are asking for, since you are saying that the code "forgot" the task.

To observe the exception, you cannot β€œforget” the task:

 public Task OtherMethodAsync() { ... return DoSomethingAsync(); } 

And at some point, await (or Wait ) is the returned task. This is how you know that the task will be completed and completed.

+5
source

ASP.NET usually does not allow fire-and-forget operations (async void) from a request. See fooobar.com/questions/966503 / ... for a further explanation of this behavior and some possible workarounds.

+2
source

All Articles