Nasty exceptions in Timer scope

Unhandled exceptions occurring in Timer scope in a .Net Core application will crash the application

Björn Weström

2 minute read

TL; DR

Unhandled exceptions occurring in Timer scope in a .Net Core application will crash the application without any logs or any graceful shutdown. Make sure to catch any exceptions in Timer scope and handle them without rethrowing.

Timer scope

With Timer scope I refer to any method that is set to execute when a Timer fires. Typically the code would look something like this:

var timer = new System.Threading.Timer(MethodInTimerScope);
...
private void MethodInTimerScope(object state)
{
    // Perform Timer based task
}

Exceptions in Timer scope

When an unhandled exception occurs within request scope (anything initiated from an incoming HTTP request through a Controller), it will be caught by a default exception handler. The exception will be logged and the request will receive a 500 response. Similarly, when an exception occurs during application startup, shutdown, or inside a Background task (such as a BackgroundService), it is nicely logged and handled appropriately.

However, when an unhandled exception occurs within Timer scope, it seems this scope is out of reach for the regular catch-alls of exceptions. It causes the whole application to crash immediately, without leaving any clues behind in the logs.

Avoiding hard crashes from Timer scope exceptions

The key to avoiding this situation is to catch any exceptions within the Timer scope to log and handle them. If the exceptions are so severe that the application should shut down, a graceful shutdown operation can be initiated using the IHostApplicationLifetime.StopApplication() method.

Disclaimer

This applies for .Net Core 3.1 and above. Has been tested on Windows with IIS hosting, and on OS X from Visual Studio.