gotchacsharpdotnetCritical
IHostedService: background services must handle exceptions to avoid host shutdown
Viewed 0 times
.NET 6+
BackgroundService exceptionIHostedService crashStopHostbackground service retryExecuteAsync exception handling
Error Messages
Problem
An unhandled exception in a BackgroundService.ExecuteAsync() stops the hosted service silently in .NET 5 and earlier, or shuts down the entire host in .NET 6+ (when BackgroundServiceExceptionBehavior.StopHost is the default).
Solution
Wrap the main loop in try/catch and log exceptions. Use a retry policy for transient failures:
Configure exception behavior:
public class WorkerService : BackgroundService
{
private readonly ILogger<WorkerService> _logger;
public WorkerService(ILogger<WorkerService> logger)
=> _logger = logger;
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
try
{
await DoWorkAsync(stoppingToken);
}
catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested)
{
break; // normal shutdown, exit cleanly
}
catch (Exception ex)
{
_logger.LogError(ex, "Worker iteration failed — retrying in 5s");
await Task.Delay(TimeSpan.FromSeconds(5), stoppingToken);
}
}
}
}Configure exception behavior:
builder.Services.Configure<HostOptions>(o =>
o.BackgroundServiceExceptionBehavior = BackgroundServiceExceptionBehavior.Ignore);Why
BackgroundService.ExecuteAsync is called on a fire-and-forget Task from StartAsync. In .NET 6 the host monitors this task and calls IHostApplicationLifetime.StopApplication() when it faults, bringing down the whole process.
Gotchas
- OperationCanceledException from stoppingToken is expected on shutdown — don't log it as an error
- Using IServiceScopeFactory is required to access scoped services inside the background service loop
- Channel.Writer.TryComplete(exception) signals consumers; check channel reader for completion
Revisions (0)
No revisions yet.