BackgroundService Gotcha: Silent Failures
I know last time I talked about
BackgroundService… I don’t want to make this a series or anything, but there is another common “gotcha” when it comes to
BackgroundService: exceptions are silently ignored.
ExecuteAsync implementation throws an exception, that exception is silently swallowed and ignored. This is because
BackgroundService captures the task from
ExecuteAsync but never
awaits it - i.e.,
BackgroundService uses fire-and-forget.
This problem will surface as
BackgroundService instances just stopping, without any indication of a problem. What actually happens if
ExecuteAsync throws an exception is that the exception is captured and placed on the
Task that was returned from
ExecuteAsync. The problem is that
BackgroundService doesn’t observe that task, so there’s no logging and no process crash - the
BackgroundService has completed executing but it just sits there doing nothing.
This is not necessarily a problem with
BackgroundService; fire-and-forget can be appropriate for “top-level” loops such as a background worker task. However, it would be nice to have logging at least, so this “gotcha” is detectable.
All top-level loops should have a
catch with some kind of reporting if something goes wrong.
ExecuteAsync implementations are top-level loops, so they should have a top-level
try that catches all exceptions:
I recommend you combine this solution with the solution from last time that uses
Task.Run to avoid startup problems: