Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detect shutdown signal from docker when using Generic Host IHostBuilder

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:

  1. How can i detect the docker shutdown command?
  2. How can i register both methods of shutdown (via console or docker) depending on the method by which i am calling (at times I may debug directly in Visual Studio as a console, whereas mostly i would use via docker, but would be nice to auto-register for both scenarios).

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

like image 427
morleyc Avatar asked Jul 08 '20 20:07

morleyc


1 Answers

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.

like image 55
Orphid Avatar answered Sep 21 '22 00:09

Orphid