I am using the .NET Core Generic Host (not Web Host) to build a Console app that needs a rather lengthy graceful shutdown. From the source code in
aspnet/Hosting/src/Microsoft.Extensions.Hosting/HostOptions
it seems pretty clear that the ShutdownTimeout
option can be used to change the shutdown timeout in the cancellation token that is provided as a parameter to ShutdownAsync
. By default it is 5 seconds.
However, I can't figure out where and how to write the code to specify this option in the HostBuilder
configuration code that you typically put in the Program.cs
file.
Can someone post some code that shows how to do this?
NET Generic Host in ASP.NET Core. The ASP.NET Core templates create a WebApplicationBuilder and WebApplication, which provide a streamlined way to configure and run web applications without a Startup class. For more information on WebApplicationBuilder and WebApplication , see Migrate from ASP.NET Core 5.0 to 6.0.
In your main program, you can create an application builder and an application. The Environment (as a IWebHostEnvironment ) is available on both objects. var builder = WebApplication. CreateBuilder(args); var environment = builder.
CreateDefaultBuilder performs the following tasks: Configures Kestrel server as the web server using the app's hosting configuration providers. For the Kestrel server's default options, see Configure options for the ASP.NET Core Kestrel web server. Sets the content root to the path returned by Directory.
NET Generic Host, which is a non-web version of the WebHost that runs ASP.NET Core. In ASP.NET Core 3.0 and 3.1, they moved ASP.NET to run on . NET Generic Host instead of the previously used WebHost. The reason is that the WebHost builder was tied more to HTTP requests and worked well for Web applications.
OK, I finally figured it out ... Here's an outline the configuration code in my Program.cs Main function, with most of the items elided, to show where the configuration for HostOptins.ShutdownTimeout goes.
public static async Task Main(string[] args)
{
var host = new HostBuilder()
.ConfigureHostConfiguration(configHost => {...})
.ConfigureAppConfiguration((hostContext, configApp) => {...})
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<ApplicationLifetime>();
...
services.Configure<HostOptions>(
opts => opts.ShutdownTimeout = TimeSpan.FromSeconds(10));
})
.ConfigureLogging(...)
.UseConsoleLifetime()
.Build();
try
{
await host.RunAsync();
}
catch(OperationCanceledException)
{
; // suppress
}
}
To make the this work, here is the StopAsync method in my IHostedService class:
public async Task StopAsync(CancellationToken cancellationToken)
{
try
{
await Task.Delay(Timeout.Infinite, cancellationToken);
}
catch(TaskCanceledException)
{
_logger.LogDebug("TaskCanceledException in StopAsync");
// do not rethrow
}
}
See Graceful shutdown with Generic Host in .NET Core 2.1 for more details about this.
Btw, the catch block in Program.Main
is necessary to avoid an unhandled exception, even though I am catching the exception generated by awaiting the cancellation token in StopAsync
; because it seems that an unhandled OperationCanceledException
is also generated at expiration of the shutdown timeout by the framework-internal version of StopAsync
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With