Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't log an error when a BackgroundService is canceled due to the host being stopped. #57005

Merged
merged 6 commits into from
Aug 10, 2021
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ internal sealed class Host : IHost, IAsyncDisposable
private readonly IHostEnvironment _hostEnvironment;
private readonly PhysicalFileProvider _defaultProvider;
private IEnumerable<IHostedService> _hostedServices;
private volatile bool _stopCalled;

public Host(IServiceProvider services,
IHostEnvironment hostEnvironment,
Expand Down Expand Up @@ -84,6 +85,13 @@ private async Task TryExecuteBackgroundServiceAsync(BackgroundService background
}
catch (Exception ex)
{
// When the host is being stopped, it cancels the background services.
// This isn't an error condition, so don't log it as an error.
if (_stopCalled && backgroundService.ExecuteTask.IsCanceled && ex is OperationCanceledException)
{
return;
}

_logger.BackgroundServiceFaulted(ex);
if (_options.BackgroundServiceExceptionBehavior == BackgroundServiceExceptionBehavior.StopHost)
{
Expand All @@ -95,6 +103,7 @@ private async Task TryExecuteBackgroundServiceAsync(BackgroundService background

public async Task StopAsync(CancellationToken cancellationToken = default)
{
_stopCalled = true;
_logger.Stopping();

using (var cts = new CancellationTokenSource(_options.ShutdownTimeout))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1367,6 +1367,45 @@ public async Task BackgroundServiceAsyncExceptionGetsLogged(
}
}

/// <summary>
/// Tests that when a BackgroundService is canceled when stopping the host,
/// no error is logged.
/// </summary>
[Fact]
public async Task HostNoErrorWhenServiceIsCanceledAsPartOfStop()
{
using TestEventListener listener = new TestEventListener();
eerhardt marked this conversation as resolved.
Show resolved Hide resolved

using IHost host = CreateBuilder()
.ConfigureLogging(logging =>
{
logging.AddEventSourceLogger();
})
.ConfigureServices(services =>
{
services.AddHostedService<AsyncWaitingService>();
})
.Build();

host.Start();
await host.StopAsync();

EventWrittenEventArgs[] events =
listener.EventData.Where(
e => e.EventSource.Name == "Microsoft-Extensions-Logging").ToArray();

foreach (EventWrittenEventArgs eventArg in events)
{
int levelIndex = eventArg.PayloadNames.IndexOf("Level");
LogLevel level = (LogLevel)eventArg.Payload[levelIndex];
Assert.True(level < LogLevel.Error);

int eventNameIndex = eventArg.PayloadNames.IndexOf("EventName");
string eventName = (string)eventArg.Payload[eventNameIndex];
Assert.NotEqual("BackgroundServiceFaulted", eventName);
}
}

private IHostBuilder CreateBuilder(IConfiguration config = null)
{
return new HostBuilder().ConfigureHostConfiguration(builder => builder.AddConfiguration(config ?? new ConfigurationBuilder().Build()));
Expand Down Expand Up @@ -1513,5 +1552,18 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
throw new Exception("Background Exception");
}
}

private class AsyncWaitingService : BackgroundService
{
public AsyncWaitingService() { }

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
await Task.Delay(1000, stoppingToken);
}
eerhardt marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
}