Application restarts are a normal part of modern deployments. Kubernetes rolls out new container versions, Azure App Service performs maintenance, Docker containers are replaced, and virtual machines restart after updates. If an application shuts down abruptly, in-flight requests may fail, background jobs may be interrupted, and queued messages can be lost.
ASP.NET Core includes built-in support for graceful shutdown, allowing applications to stop accepting new requests while completing existing work before the process exits. Proper shutdown handling improves reliability, prevents data corruption, and minimizes service interruptions during deployments.
Rather than simply stopping the application process, this article explains how to implement graceful shutdown in ASP.NET Core and safely handle background operations during application termination.
Note: Graceful shutdown is especially important for applications that process background jobs, consume message queues, or perform long-running operations.
Why Graceful Shutdown Matters
Abrupt application termination can result in:
Interrupted HTTP requests
Lost background jobs
Incomplete database transactions
Duplicate message processing
Corrupted file operations
Failed deployments
Allowing the application to finish ongoing work before stopping reduces operational risks.
Common Shutdown Scenarios
Graceful shutdown is important during:
Kubernetes rolling updates
Docker container replacement
Azure App Service restarts
IIS application recycling
Virtual machine maintenance
Manual deployments
Auto-scaling events
These scenarios occur regularly in production environments.
Graceful Shutdown Flow
flowchart LR
A[Shutdown Signal]
B[ASP.NET Core Host]
C[Stop Accepting Requests]
D[Complete Active Requests]
E[Stop Background Services]
F[Application Exits]
A --> B
B --> C
C --> D
D --> E
E --> F
The application first stops accepting new requests, completes ongoing work, and then shuts down cleanly.
Understanding Application Lifetime
ASP.NET Core exposes application lifetime events through IHostApplicationLifetime.
Inject the service:
public class StartupService
{
private readonly IHostApplicationLifetime _lifetime;
public StartupService(
IHostApplicationLifetime lifetime)
{
_lifetime = lifetime;
}
}
This service provides notifications when the application starts, stops, or is shutting down.
Registering Shutdown Callbacks
Execute cleanup logic before the application exits.
_lifetime.ApplicationStopping.Register(() =>
{
Console.WriteLine(
"Application is shutting down...");
});
Use this callback to release resources, stop background processing, or flush pending operations.
Handling Cancellation Tokens
Background services receive a cancellation token when shutdown begins.
public class Worker : BackgroundService
{
protected override async Task ExecuteAsync(
CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
await ProcessQueueAsync();
await Task.Delay(
1000,
stoppingToken);
}
}
}
Checking the cancellation token allows the service to exit cleanly without abruptly terminating work.
Completing In-Flight Requests
Long-running operations should observe request cancellation.
[HttpGet]
public async Task<IActionResult> GenerateReport(
CancellationToken cancellationToken)
{
await reportService.GenerateAsync(
cancellationToken);
return Ok();
}
Passing cancellation tokens throughout the application enables cooperative shutdown.
Configuring Shutdown Timeout
Applications may require additional time to complete ongoing work.
Join the conversation! Your thoughts help the community grow.