Back to results for “Background Services”
.NET › Background Services

How should exceptions be handled inside a BackgroundService's ExecuteAsync loop to prevent the entire service from crashing silently?

Intermediate

Answer

An unhandled exception escaping ExecuteAsync causes the BackgroundService to stop entirely (and by default, in .NET 6+, can even trigger the whole host to shut down if configured), so production code should wrap individual work iterations in try/catch, log the exception, and continue the loop -- reserving unhandled propagation only for truly fatal, unrecoverable conditions.
protected override async Task ExecuteAsync(CancellationToken stoppingToken) {
    while (!stoppingToken.IsCancellationRequested) {
        try {
            await ProcessBatchAsync();
        } catch (Exception ex) {
            _logger.LogError(ex, "Batch processing failed, will retry next cycle");
        }
        await Task.Delay(TimeSpan.FromSeconds(30), stoppingToken);
    }
}
Real-world example A background service silently stopped processing for three days after an unhandled exception in one iteration terminated the whole loop -- a fix wraps each iteration's work in try/catch so a single bad message no longer takes down the entire background processor.

Common follow-ups: What is the BackgroundServiceExceptionBehavior option added in .NET 6?;How do you get alerted when a background service has stopped unexpectedly?