Waiting for a non-essential metrics to be sent makes no sense to me, as it adds latency (waiting for the server's response) on each call to the back-end dotnet core service, which might happen multiple times per client call. Still, logging an error on failure is important (I do not need to throw it though, as the metric's failure should not impact the service).
I found multiple ways of doing so. Here is the method to be called in a FireAndForget manner:
public async Task FireAndForget()
{
try{ await sendTheMetric(); } // Try catch on the await, to log exceptions
catch(Exception e){ logger.debug(e) }
}
Method 1: Remove the await.
FireAndForget(); // No await in front of the call
Method 2: Seems similar to method 1 to me, as we do not await the Task.Factory.StartNew call.
Task.Factory.StartNew(async () => await MyAsyncTask());
Method 3: Enqueue on the ThreadPool as a workItem.
ThreadPool.QueueUserWorkItem(async o => await FireAndForget());
I have a hard time finding which one I should use for a Fire and forget call to send a non-essential metric. My goal is to not add latency to each calls to my service each time a metric is sent. Logging an error when the metrics fails to be sent is important, but it should never re-throw. The thread context is not important for the execution of the task. The task should always, or at least almost always, be completed.
Which one is the best practice for for requirements? Or are they all the same?
Note: I did not include async void
, as it seems risky (if an exception occurs, it might crash, as no Task will wrap it).
Fire-and-Forget is most effective with asynchronous communication channels, which do not require the Originator to wait until the message is delivered to the Recipient. Instead, the Originator can pursue other tasks as soon as the messaging system has accepted the message.
The call to the async method starts an asynchronous task. However, because no Await operator is applied, the program continues without waiting for the task to complete. In most cases, that behavior isn't expected.
Hope this doesn't muddy the water but there is a 4th option that (from what i have read) is becoming a more accepted option.
Starting with C#7.0 you have the option of using a discard for this sort of instance.
_ = FireAndForget();
This essentially indicates that the task is not needed and thus no return value is expected. Seems to be recommended over Method 1 as it means you are explicitly indicating that it is "fire and forget" (which is less ambiguous and does not look like a coding mistake).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With