Search code examples
c#.net-coretaskblazor-server-sidecancellation-token

What is the best way to create a background Task for an ILogger


I created a File ILogger provider. It has a background task that does the actual writing to disk so that a Log() call is not waiting for a disk write to complete.

What is the best way to create/manage this background task? I can put it in a Task.Run() that I then forget about. But that strikes me as problematic.

In addition, the ILogger.Provider.Dispose() is never called. I want the task to be disposed so it can close the file it has open.

And, when Dispose() is called, I need to end the loop inside the Task.Run(). Is it better in this case to just have a bool I set? Or should I use a CancellationToken?


Solution

  • Discussing this with a number of developers I respect, the consensus was two-fold. First, use a thread:

    public void Start()
    {
        _workerThread = new Thread(ProcessQueue)
        {
            IsBackground = true,
            Priority = ThreadPriority.BelowNormal
        };
        _workerThread.Start();
    }
    

    The second part was something I hadn't thought of. Use synchronous calls. No async/await, no Tasks. We're all so set on async everything we don't stop to think. But if the code in the thread is going to write to the log file, and that's the only thing it's doing, you want all that happening in the thread.

    There's no advantage to creating tasks and there are disadvantages. So...

    private void ProcessQueue()
    {
        while (!_cancellationTokenSource.IsCancellationRequested)
        {
            _newItemEventSlim.Wait(_cancellationTokenSource.Token);
    
            var lines = new List<string>();
            while (_queue.TryDequeue(out var message))
                lines.Add(message);
            WriteLine(lines);
    
            Flush();
    
            _newItemEventSlim.Reset();
        }
    }
    

    WriteLine() and Flush() are both synchronous. Because what would you gain by having them be async?