BackgroundService Gotcha: Service Lifetime is Independent from Application Lifetime
OK, I guess I do have a series on my hands.
This one isn’t so much a “gotcha” as it is a common mistake. Hosted services (including
BackgroundServices) have a lifetime that is independent from their host. This means that if a
BackgroundService exits, its host will not exit. And a host will happily continue running even if all its services have exited.
This mistake is most common when writing a kind of “subscriber” or “backend processor” application - something that listens to a queue and processes messages on that queue. For these kinds of applications, it’s common to have a .NET Core host with only a single hosted service, and the service has a loop which processes messages from the queue. This is essentially the “ASP.NET Core Worker Process” template project in Visual Studio. When writing this kind of application, it’s easy to forget about the host, and treat the hosted service as the application. But when there are no more messages (or some other shutdown signal is delivered to the hosted service) and the service exits, then the host application stays around.
This behavior is by design. If a
BackgroundService implementation wants the application to exit when it stops (or has a fatal error), it needs to do that itself by injecting an
IHostApplicationLifetime and calling
At this point, this is a fair amount of boilerplate code to go into each background service. Production code bases should probably define a “critical background service” base type that handles all the wrapper code so background services only need to define the
// Implementation part.