Skip to content

BackgroundService cancellation is logged as failure if host is still starting #98935

@mus65

Description

@mus65

Description

When a BackgroundService is cancelled while the host is still starting, the OperationCanceledException is logged as an error instead of being ignored. This is because the following code checks for "_stopCalled" which is not set in this case:

if (_stopCalled && backgroundTask.IsCanceled && ex is OperationCanceledException)

We have seen this happen when an IIS recycle was triggered while the host is still starting. But it can also be reproduced in a console app, see reproduction steps.

Reproduction Steps

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

HostApplicationBuilder builder = Host.CreateApplicationBuilder();
builder.Services.AddHostedService<ABackgroundService>();
builder.Services.AddHostedService<ASlowStartService>();
var host = builder.Build();

var lifetime = host.Services.GetRequiredService<IHostApplicationLifetime>();
_ = host.StartAsync();
await Task.Delay(TimeSpan.FromSeconds(1));
lifetime.StopApplication();
await Task.Delay(TimeSpan.FromSeconds(1));
await host.WaitForShutdownAsync();

internal class ABackgroundService : BackgroundService
{
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        await Task.Delay(Timeout.Infinite, stoppingToken);
    }
}

internal class ASlowStartService : IHostedService
{
    public async Task StartAsync(CancellationToken cancellationToken)
    {
        await Task.Delay(TimeSpan.FromSeconds(10), CancellationToken.None);
    }

    public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}

Expected behavior

Exception is ignored.

Actual behavior

Exception is logged:

fail: Microsoft.Extensions.Hosting.Internal.Host[9]
      BackgroundService failed
      System.Threading.Tasks.TaskCanceledException: A task was canceled.
         at ABackgroundService.ExecuteAsync(CancellationToken stoppingToken)
         at Microsoft.Extensions.Hosting.Internal.Host.TryExecuteBackgroundServiceAsync(BackgroundService backgroundService)
crit: Microsoft.Extensions.Hosting.Internal.Host[10]
      The HostOptions.BackgroundServiceExceptionBehavior is configured to StopHost. A BackgroundService has thrown an unhandled exception, and the IHost instance is stopping. To avoid this behavior, configure this to Ignore; however the BackgroundService will not be restarted.
      System.Threading.Tasks.TaskCanceledException: A task was canceled.
         at ABackgroundService.ExecuteAsync(CancellationToken stoppingToken)
         at Microsoft.Extensions.Hosting.Internal.Host.TryExecuteBackgroundServiceAsync(BackgroundService backgroundService)

Regression?

No response

Known Workarounds

No response

Configuration

.NET 8.0.2
Windows x64

Other information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions