Как правильно убить ASP. NET Базовое приложение для перезапуска docker контейнера - PullRequest
0 голосов
/ 11 марта 2020

У меня есть простое ASP. NET Core Web API-приложение, которое запускается в docker контейнере.

Это приложение должно обрабатывать HTTP-запросы и принимать события от Kafka. Итак, в методе Startup.Configure я запускаю выделенный поток с бесконечностью l oop для использования событий.

public void Consume()
{
    Task.Factory.StartNew(async () =>
    {
        try
        {
            while (true)
            {
                var eventMsg = _consumer.Consume();
                await Handle(eventMsg);
            }
        }
        catch (Exception ex)
        {
            _consumer.Close();
                    // log error
            throw;
        }
    }, TaskCreationOptions.LongRunning);
}

Затем при запуске

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseHsts();
            }

            app.UseAuthentication();
            app.UseMvc();

            var consumer = app.ApplicationServices.GetRequiredService<KafkaConsumer>();
            consumer.Consume();
        }

Но когда ошибка возникает в l oop Мне нужно перезапустить контейнер с приложением. В простом приложении, когда я добавляю throw;, оно генерирует необработанное исключение, закрывает приложение и в контейнере результатов перезапускается. Но в этом случае throw; не помогло, потому что он выбрасывает в фоновом потоке, и я не жду результата. Я не жду результата, потому что, когда я добавляю

await consumer.Consume();

, он останавливает все приложения и WebAPI не запускается.

Как правильно с этим справиться? Если коротко, мне нужно выбросить исключение в фоновом потоке, а затем закрыть приложение, чтобы автоматически перезапустить контейнер. Я не могу добавить Application.Exit к Consume методу, потому что это библиотека, и я не могу изменить код.

Есть ли другой способ убить приложение из фонового потока?

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

1 Ответ

5 голосов
/ 11 марта 2020

Это приложение должно обрабатывать HTTP-запросы и принимать события от Kafka. Итак, в методе Startup.Configure я запускаю выделенный поток с бесконечностью l oop для использования событий.

Правильный способ запуска фоновой службы на ASP. NET Core. - использовать размещенные сервисы. Таким образом, ваш код будет выглядеть так:

public class KafkaConsumer : BackgroundService
{
  public KafkaConsumer()
  {
    _consumer = ...;
  }

  protected override Task ExecuteAsync(CancellationToken stoppingToken) => Task.Run(async () => 
  {
    try
    {
      while (true)
      {
        var eventMsg = _consumer.Consume();
        await Handle(eventMsg);
      }
    }
    catch (Exception ex)
    {
      _consumer.Close();
      ... // log error
      throw;
    }
  });
}

и он зарегистрирован в вашем классе запуска примерно так:

public void ConfigureServices(IServiceCollection services)
{
  services.AddHostedService<KafkaConsumer>();
}

Но когда происходит ошибка в l oop Мне нужно перезапустить контейнер с приложением.

Для этого введите IHostApplicationLifetime и позвоните StopApplication:

public class KafkaConsumer : BackgroundService
{
  private IHostApplicationLifetime _hostApplicationLifetime;

  public KafkaConsumer(IHostApplicationLifetime hostApplicationLifetime)
  {
    _hostApplicationLifetime = hostApplicationLifetime;
    _consumer = ...;
  }

  protected override Task ExecuteAsync(CancellationToken stoppingToken) => Task.Run(async () => 
  {
    try
    {
      while (true)
      {
        var eventMsg = _consumer.Consume();
        await Handle(eventMsg);
      }
    }
    catch (Exception ex)
    {
      _consumer.Close();
      ... // log error
      _hostApplicationLifetime.StopApplication();
      throw;
    }
  });
}
...