Обнаружение сигнала выключения от docker при использовании Generi c Host IHostBuilder - PullRequest
7 голосов
/ 08 июля 2020

У меня есть стандартный c построитель хоста по умолчанию, как показано ниже:

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();
}

Я использую UseConsoleLifetime и docker для запуска приложения, оно запускается, но мне кажется,

Я аккуратно отправляю сигнал остановки своему приложению с помощью команды docker stop в PowerShell.

Однако, в отличие от моего консольного приложения, в котором я нажимаю control + C, приложение не получает эту команду остановки и через 10 секунд принудительно завершается.

Мои вопросы:

  1. Как я могу обнаружить команду docker выключения?
  2. Как я могу зарегистрировать оба метода выключения (через консоль или docker) в зависимости от метода, которым я звоню (иногда я могу отлаживать непосредственно в Visual Studio в качестве консоли, тогда как в основном я бы использовал через docker, но было бы неплохо автоматически зарегистрировать оба сценария ios).

ИЗМЕНИТЬ И ОБНОВИТЬ

Я видел ответы, спасибо, упоминание ловушки на AppDomain.CurrentDomain.ProcessExit.

Для моего рабочего BackgroundService интерфейс таков, что он имеет функцию:

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);
        }
    }
}

Использование UseConsoleLifetime всякий раз, когда отправляется ctrl + c, устанавливается stoppingToken.

При использовании того же кода (включая UseConsoleLifetime тот же код) в пределах docker, stoppingToken не установлен.

Обратите внимание, я не вижу, что у меня есть доступ к этому источнику токенов, чтобы выполнить отмену.

Если я Зарегистрируйтесь в AppDomain.CurrentDomain.ProcessExit, как я могу использовать это для установки stoppingToken (в отличие от создания собственного источника токена остановки, поскольку, хотя это возможно, хотелось бы избежать, если это возможно).

docker стоп

1 Ответ

5 голосов
/ 08 июля 2020

docker stop отправляет сигнал SIGTERM основному процессу в контейнере. Чтобы справиться с этим и корректно завершить работу, вам необходимо перехватить этот сигнал и выполнить соответствующий код завершения. Этот вопрос SO описывает, как вы можете прикрепить обработчик событий, который отвечает на этот сигнал.

Обратите внимание, что если вы не перехватите этот сигнал, docker принудительно уничтожит контейнер после тайм-аут (по умолчанию 10 секунд).

Для обработки обоих, вы можете извлечь любой код очистки, который вы запускаете, чтобы корректно завершить работу функции, и вызвать ее из обоих обработчиков.

...