Description
When a Microsoft.Extensions.Hosting.BackgroundService running in the default Microsoft.Extensions.Hosting.IHost throws an exception from its ExecuteAsync method and HostOptions.BackgroundServiceExceptionBehavior is set to BackgroundServiceExceptionBehavior.StopHost (the default), the host is stopped. As a result, awaiting RunAsync or StopAsync on the host completes and the application typically exits.
Previously, awaiting RunAsync or StopAsync on the host completed successfully and this usually meant the application exited with a success exit code (zero).
Now, awaiting RunAsync or StopAsync on the host will throw an exception, which will usually mean that the application will exit with a failure exit code (non-zero).
Version
.NET 11 Preview 3
Previous behavior
When a BackgroundService throws an exception from its ExecuteAsync method and HostOptions.BackgroundServiceExceptionBehavior is set to BackgroundServiceExceptionBehavior.StopHost, the task returned from calling RunAsync , StopAsync or WaitForShutdownAsync on the default host completes successfully.
New behavior
When a BackgroundService throws an exception from its ExecuteAsync method and HostOptions.BackgroundServiceExceptionBehavior is set to BackgroundServiceExceptionBehavior.StopHost, the task returned from calling RunAsync, StopAsync or WaitForShutdownAsync on the default host fails with an exception. If a single service fails, the exception thrown by the service is rethrown. If multiple services fail, their exceptions are combined into an AggregateException.
Type of breaking change
Reason for change
If an application stops because of a failure, the application shouldn't exit with a success exit code. The previous behavior was effectively hiding the failure, making it harder to detect and diagnose the issue that caused the exception.
Recommended action
The recommended action is to do nothing: a failing application should exit with a failure exit code, which is the new behavior.
If it is necessary to maintain the previous behavior (success exit code), wrap the await of RunAsync or StopAsync on the host in a try-catch block.
Feature area
Extensions
Affected APIs
IHost.StopAsync with the default implementation of IHost and any methods that call it:
HostingAbstractionsHostExtensions.RunAsync
HostingAbstractionsHostExtensions.Run
HostingAbstractionsHostExtensions.StopAsync
HostingAbstractionsHostExtensions.WaitForShutdownAsync
HostingAbstractionsHostExtensions.WaitForShutdown
Further information
The relevant PR is dotnet/runtime#124863 and the issue is dotnet/runtime#67146.
Associated WorkItem - 560726
Description
When a
Microsoft.Extensions.Hosting.BackgroundServicerunning in the defaultMicrosoft.Extensions.Hosting.IHostthrows an exception from itsExecuteAsyncmethod andHostOptions.BackgroundServiceExceptionBehavioris set toBackgroundServiceExceptionBehavior.StopHost(the default), the host is stopped. As a result,awaitingRunAsyncorStopAsyncon the host completes and the application typically exits.Previously,
awaitingRunAsyncorStopAsyncon the host completed successfully and this usually meant the application exited with a success exit code (zero).Now,
awaitingRunAsyncorStopAsyncon the host will throw an exception, which will usually mean that the application will exit with a failure exit code (non-zero).Version
.NET 11 Preview 3
Previous behavior
When a
BackgroundServicethrows an exception from itsExecuteAsyncmethod andHostOptions.BackgroundServiceExceptionBehavioris set toBackgroundServiceExceptionBehavior.StopHost, the task returned from callingRunAsync,StopAsyncorWaitForShutdownAsyncon the default host completes successfully.New behavior
When a
BackgroundServicethrows an exception from itsExecuteAsyncmethod andHostOptions.BackgroundServiceExceptionBehavioris set toBackgroundServiceExceptionBehavior.StopHost, the task returned from callingRunAsync,StopAsyncorWaitForShutdownAsyncon the default host fails with an exception. If a single service fails, the exception thrown by the service is rethrown. If multiple services fail, their exceptions are combined into anAggregateException.Type of breaking change
Reason for change
If an application stops because of a failure, the application shouldn't exit with a success exit code. The previous behavior was effectively hiding the failure, making it harder to detect and diagnose the issue that caused the exception.
Recommended action
The recommended action is to do nothing: a failing application should exit with a failure exit code, which is the new behavior.
If it is necessary to maintain the previous behavior (success exit code), wrap the
awaitofRunAsyncorStopAsyncon the host in atry-catchblock.Feature area
Extensions
Affected APIs
IHost.StopAsyncwith the default implementation ofIHostand any methods that call it:HostingAbstractionsHostExtensions.RunAsyncHostingAbstractionsHostExtensions.RunHostingAbstractionsHostExtensions.StopAsyncHostingAbstractionsHostExtensions.WaitForShutdownAsyncHostingAbstractionsHostExtensions.WaitForShutdownFurther information
The relevant PR is dotnet/runtime#124863 and the issue is dotnet/runtime#67146.
Associated WorkItem - 560726