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.
Top comments (0)