Fire and Forget Approach

Fire and Forget approach

It depends on the semantics you want. If you want to ensure exceptions are noticed, then yes, you could await the task. But in that case it's not truly "fire and forget".

A true "fire and forget" - in the sense that you don't care about when it completes or whether it completes successfully or with error - is extremely rare.

Edit:

For handling exceptions:

public static async void Forget(this Task task, params Type[] acceptableExceptions)
{
try
{
await task.ConfigureAwait(false);
}
catch (Exception ex)
{
// TODO: consider whether derived types are also acceptable.
if (!acceptableExceptions.Contains(ex.GetType()))
throw;
}
}

Note that I recommend using await instead of ContinueWith. ContinueWith has a surprising default scheduler (as noted on my blog) and Task.Exception will wrap the actual exception in an AggregateException, making the error handling code more cumbersome.

Simplest way to do a fire and forget method in C#?


ThreadPool.QueueUserWorkItem(o => FireAway());

(five years later...)

Task.Run(() => FireAway());

as pointed out by luisperezphd.

Correct way to implement fire and forget async method call


In my project, I have a network call to sending Email, I don't want to wait for the response, because the most likely Email provider sends the Emails successfully.

Most email providers work by having you send into a queue, and then the actual email is sent later, when they process work out of that queue. So, sending into the queue is fast and very reliable.

So this means that your SendEmailAsync or whatever API should be quite fast, and shouldn't require returning early. Since SendEmailAsync actually sends to a queue, the only thing it represents is "please accept my request to send this email".

Which of the following methods is better and what is the difference?

Neither.

Since sending emails is just a queue write, and you don't want your request to be lost, the appropriate approach is not to use fire-and-forget at all:

public async Task<IActionResult> Index()
{
await SendAsync();
return View();
}

private async Task SendAsync()
{
_logger.LogInformation("Before");
await Task.Delay(10000); // Email send
_logger.LogInformation("After");
}

If, for some reason, you're using an email provider that doesn't queue, then you can create your own queue (Azure Storage Queue, Amazon SQS, RabbitMQ, etc) and change SendAsync to write a message to that queue. Then have a separate background process (Azure Function, Amazon Lambda, etc) read from that queue and send the emails to the email provider.

Fire and forget, using `Task.Run` or just calling an async method without `await`


In general especially when it comes to libraries or console apps, in order to fire and forget an async method, is it better to just call the async method without awaiting it or use Task.Run?

In general, it's best not to use fire-and-forget at all.

"Fire and forget" means:

  1. You don't care if the code has an exception. Any exceptions will cause it to fail silently; no logging, no notification, etc.
  2. You don't need to know when the code completes. I.e., the consuming application doesn't ever need to wait for the code to complete. Even during shutdown.
  3. You don't need the code to complete. As a corollary of (2), fire-and-forget code may not run to completion; and as a corollary of (1), you would have no notification that it failed to complete.

In short, "fire and forget" is only appropriate for an extremely small number of tasks. E.g., updating a cache. I'd say probably 85% or more of "fire and forget" code is wrong - it's using fire and forget for code that should not be fire and forget.

So I'd say the best solution is to not use fire and forget at all. At the very least, you should expose a Task somewhere that represents a "followup action". Consider adding the Task to your return type or exposing it as a property.

Adopting fire and forget - especially in a library - means you're forcing all consumers to never know when it's safe to shut down and exit. But if you really want to do fire and forget, there are a few options.

A. One option is calling an async void function without a context. The consuming application still has no way to determine if/when the code completes, but at least that way exceptions are not ignored.

B. Another option is to start the task without a context. This option has both disadvantages of fire and forget code: exceptions are ignored and the calling code cannot know when it completes.

Both of these recommendations start the task without a context. There are helpers for doing this, or you can wrap the call in Task.Run (slightly less efficient, but it works fine).

I wouldn't recommend starting the task directly. While this would work fine in a Console app, it's not appropriate for libraries which may be called in situations where a context is provided.

Fire and Forget multiple methods in C#

As you're using an Azure function you cannot have true fire and forget as you risk the function terminating before the completion of all the task(s).

However, we don't care for the result of the task, so we need not await each task individually.

System.Collections.Generic.List<System.Threading.Tasks.Task> tasks = new System.Collections.Generic.List<System.Threading.Tasks.Task>();
for (int i = 0; i < 20; i++)
{
tasks.Add(System.Threading.Tasks.Task.Run(() => ApiRef1(i, log));
}
await System.Threading.Tasks.Task.WhenAll(tasks);

This allows all the tasks to fire in parallel, but pause further execution until they're all complete, ensuring the completion of the tasks before the process is terminated.



Related Topics



Leave a reply



Submit