I have a default generic host builder as below:
public static IHostBuilder CreateDefaultBuilder(string[] args)
{
var builder = Host.CreateDefaultBuilder(args);
builder
.ConfigureLogging((hostingContext, logging) =>
{
logging.ClearProviders();
logging.AddConsole();
if (hostingContext.HostingEnvironment.IsDevelopment() == true)
logging.AddDebug();
})
.ConfigureHostConfiguration(configurationBuilder =>
{
configurationBuilder.AddCommandLine(args);
})
.ConfigureAppConfiguration((hostingContext, configApp) =>
{
var env = hostingContext.HostingEnvironment;
Console.WriteLine(env.EnvironmentName);
})
.UseConsoleLifetime();
return builder;
}
public static async Task Main(string[] args)
{
var host = CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
services.Configure<HostOptions>(option =>
{
option.ShutdownTimeout = System.TimeSpan.FromSeconds(20);
});
services.AddLogging();
services.AddSimpleInjector(container, options =>
{
// Hooks hosted services into the Generic Host pipeline while resolving them through Simple Injector
options.AddHostedService<Worker>();
// Allows injection of ILogger & IStringLocalizer dependencies into application components
options.AddLogging();
// options.AddLocalization();
});
})
.Build()
.UseSimpleInjector(container);
config.Build();
await host.RunAsync();
}
I am using UseConsoleLifetime
and docker to run the application, it runs, but i do not seem to be able to gracefully shutdown.
I gracefully send a stop signal to my application via the docker stop
command in PowerShell.
However, unlike my console app where i press control+C, the app doesn't get this stop command and after 10 seconds is killed forcibly.
My questions are please:
EDIT AND UPDATE
I have seen replies, thank you, mentioning to trap on AppDomain.CurrentDomain.ProcessExit
.
For my worker BackgroundService
the interface is such that it has the function:
public class Worker : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
logger.LogInformation("running at: {time} - stoppingToken {stoppingToken}", DateTimeOffset.Now, stoppingToken.IsCancellationRequested);
await Task.Delay(1000, stoppingToken);
}
}
}
Using the UseConsoleLifetime
whenever ctrl+c is sent, the stoppingToken is set.
When using the same code (including UseConsoleLifetime
same code as is) within docker, the stoppingToken is not set.
Note i cant see that i have access to this token source in order to perform the cancellation.
If i register to AppDomain.CurrentDomain.ProcessExit
how can i use this to set the stoppingToken (as opposed to making my own stopping token source, as whilst can be done, would like to avoid if possible).
docker stop
sends the SIGTERM signal to the primary process in the container. To handle this and gracefully shutdown, you need to trap this signal and execute the appropriate termination code. This SO question describes how you can attach an event handler that responds to this signal.
Note that if you don't trap this signal, docker will forcibly kill the container after a timeout (10 seconds by default).
To handle both, you can extract any clean up code you run to gracefully shutdown to a function, and invoke it from both handlers.
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