web-dev-qa-db-ja.com

.NET Core Worker Serviceでヘルスチェックを行う最良の方法

.NET Core Worker Serviceにヘルスチェックを実装する最良の方法は何ですか?

サービスはdocker内で実行され、サービスの状態を確認できる必要があります。

7
zby_szek

Microsoft.NET.Sdk.Workerを保持することも検討する必要があると思います。

ヘルスチェックのためだけにSDK全体を変更しないでください。

次に、バックグラウンドサービスを作成して(メインワーカーと同じように)、ファイルを更新して、たとえば現在のタイムスタンプを書き込むことができます。バックグラウンドヘルスチェックワーカーの例は次のとおりです。

public class HealthCheckWorker : BackgroundService
{
    private readonly int _intervalSec;
    private readonly string _healthCheckFileName;

    public HealthCheckWorker(string healthCheckFileName, int intervalSec)
    {
        this._intervalSec = intervalSec;
        this._healthCheckFileName = healthCheckFileName;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (true)
        {
            File.WriteAllText(this._healthCheckFileName, DateTime.UtcNow.ToString());
            await Task.Delay(this._intervalSec * 1000, stoppingToken);
        }
    }
}

次に、次のような拡張メソッドを追加できます。

public static class HealthCheckWorkerExtensions
{
    public static void AddHealthCheck(this IServiceCollection services,
        string healthCheckFileName, int intervalSec)
    {
        services.AddHostedService<HealthCheckWorker>(x => new HealthCheckWorker(healthCheckFileName, intervalSec));
    }
}

これにより、ヘルスチェックサポートをサービスに追加できます

.ConfigureServices(services =>
{
    services.AddHealthCheck("hc.txt", 5);
})
1
dkokkinos

これを行う別の方法は、IHealthCheckPublisherを実装することです。

このアプローチの利点は、既存のIHealthChecksを再利用する機能、またはIHealthCheckインターフェイスに依存するサードパーティライブラリとの統合( これ など)です。

まだターゲットにしていますがMicrosoft.NET.Sdk.Web SDKとして、asp.netの詳細を追加する必要はありません。

次に例を示します。

public static IHostBuilder CreateHostBuilder(string[] args)
{
  return Host
    .CreateDefaultBuilder(args)
    .ConfigureServices((hostContext, services) =>
    {
      services
        .AddHealthChecks()
        .AddCheck<RedisHealthCheck>("redis_health_check")
        .AddCheck<RfaHealthCheck>("rfa_health_check");

      services.AddSingleton<IHealthCheckPublisher, HealthCheckPublisher>();
      services.Configure<HealthCheckPublisherOptions>(options =>
      {
        options.Delay = TimeSpan.FromSeconds(5);
        options.Period = TimeSpan.FromSeconds(5);
      });
    });
}

public class HealthCheckPublisher : IHealthCheckPublisher
{
  private readonly string _fileName;
  private HealthStatus _prevStatus = HealthStatus.Unhealthy;

  public HealthCheckPublisher()
  {
    _fileName = Environment.GetEnvironmentVariable(EnvVariableNames.DOCKER_HEALTHCHECK_FILEPATH) ??
                Path.GetTempFileName();
  }

  public Task PublishAsync(HealthReport report, CancellationToken cancellationToken)
  {
    // AWS will check if the file exists inside of the container with the command
    // test -f $DOCKER_HEALTH_CHECK_FILEPATH

    var fileExists = _prevStatus == HealthStatus.Healthy;

    if (report.Status == HealthStatus.Healthy)
    {
      if (!fileExists)
      {
        using var _ = File.Create(_fileName);
      }
    }
    else if (fileExists)
    {
      File.Delete(_fileName);
    }

    _prevStatus = report.Status;

    return Task.CompletedTask;
  }
}
0
Veikedo