Non awaitable as "fire & forget" - is it safe to use?

I don't to use Task.Run for this kind of operation, because it's bad.

It's important to recognize/specify context for this kind of statement. Task.Run is bad on ASP.NET. It's perfectly OK to use in a GUI app on the client side.

We need to write some logs in our code.

I strongly recommend using an established logging library. Most of them work by using an in-memory queue that is (synchronously) written to by your code, and which is continually processed by a background thread. This is a pattern that is well-established.

Is it a viable solution for logging in a "fire-and-forget" mode?

One of the problems with "fire and forget" is that you don't know when there are errors. The established logging libraries all have some kind of system for dealing with errors communicating with the logging backend; the code you posted will just ignore them.

What if I create objects inside this inline method, when are they going to be GC'ed?

Conceptually, async methods act as GC "roots" as long as they are going to continue executing in the future. So local objects will be GC'ed when the method completes.


I don't to use Task.Run for this kind of operation, because it's bad.

It's not bad at all. It's just another tool in your tool belt.

It's important to understand how asynchronous methods work. Asynchronous methods all start running synchronously, just like any other method. The magic happens at the first await that acts on an incomplete Task. At that point, await sees the incomplete Task and the method returns. Usually it returns its own incomplete Task, unless the method is async void, then it returns nothing.

Asynchronous is not about how methods run. It's about how methods wait.

So in your code, LogMe() will start running on the same thread. Only when you are waiting for a response will a Task be returned up the call stack, and you're free to await it or not.

The time it takes to setup the request and send it isn't that much. So you won't notice it. But if you were doing something that did do some CPU-intensive work before the request, then it would be appropriate to use Task.Run, since that tells it to start on a different thread, so it doesn't hold you up.

If this was ASP.NET (not Core), then you may benefit from either using Task.Run, or using .ConfigureAwait(false) on the PostAsync, because otherwise it will try to come back to the same synchronization context (the context of the current incoming HTTP request), which means the current request cannot complete before LogMe() completes.

However, if you are going to fire and forget then keep in mind that whatever started the operation will have no idea if it succeeds. You should use try/catch inside LogMe if you want to log failures somewhere else (a text file or something). PostAsync will throw an exception if there was a problem sending the request (DNS lookup failure, no response, etc).

Tags:

C#

Async Await