C# 在.NET核心工作程序服务中执行运行状况检查
如何在.NET核心工作者服务中实现健康检查C# 在.NET核心工作程序服务中执行运行状况检查,c#,docker,.net-core,service,C#,Docker,.net Core,Service,如何在.NET核心工作者服务中实现健康检查 该服务将在Docker内部运行,并且需要能够检查服务的运行状况。我所做的是将Microsoft.NET.Sdk.Web添加到我的工作程序中,然后配置一个Web主机与工作程序一起运行: Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(builder => { builder.UseStartup<Startup>(); })
该服务将在Docker内部运行,并且需要能够检查服务的运行状况。我所做的是将Microsoft.NET.Sdk.Web添加到我的工作程序中,然后配置一个Web主机与工作程序一起运行:
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(builder =>
{
builder.UseStartup<Startup>();
})
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<Worker>();
services.AddLogging(builder =>
builder
.AddDebug()
.AddConsole()
);
});
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefault(生成器=>
{
builder.UseStartup();
})
.ConfigureServices((主机上下文,服务)=>
{
services.AddHostedService();
services.AddLogging(builder=>
建设者
.AddDebug()
.AddConsole()
);
});
这样做,剩下的就是和ASP.NET内核一样。
< P>我认为你也应该考虑保留微软.NET.SDK.Works./P> 不要仅仅因为运行状况检查而更改整个sdk 然后,您可以创建一个backgroundservice(就像主worker一样),以便更新一个文件以写入例如当前时间戳。背景健康检查工作人员的一个例子是: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));
}
}
另一种方法是实现
IHealthCheckPublisher
这种方法的好处是能够重复使用现有的IHealthCheck
s或与依赖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;
}
}
公共静态IHostBuilder CreateHostBuilder(字符串[]args)
{
返回主机
.CreateDefaultBuilder(args)
.ConfigureServices((主机上下文,服务)=>
{
服务
.AddHealthChecks()
.AddCheck(“redis\u health\u check”)
.AddCheck(“rfa_健康检查”);
services.AddSingleton();
配置(选项=>
{
选项。延迟=时间跨度。从秒(5);
options.Period=TimeSpan.FromSeconds(5);
});
});
}
公共类HealthCheckPublisher:IHealthCheckPublisher
{
私有只读字符串\u文件名;
private HealthStatus\u prevStatus=HealthStatus.不健康;
公共健康检查发布者()
{
_fileName=Environment.GetEnvironmentVariable(envariablenames.DOCKER\u HEALTHCHECK\u FILEPATH)??
Path.GetTempFileName();
}
公共任务PublishAsync(HealthReport报告,CancellationToken CancellationToken)
{
//AWS将使用命令检查该文件是否存在于容器内
//测试-f$DOCKER\u运行状况\u检查\u文件路径
var fileExists=\u prevStatus==HealthStatus.health;
if(report.Status==HealthStatus.health)
{
如果(!fileExists)
{
使用var=File.Create(_fileName);
}
}
else if(文件存在)
{
删除(_文件名);
}
_prevStatus=报告状态;
返回Task.CompletedTask;
}
}
我认为将SDK更改为Microsoft.NET.SDK.Web不值得。你会仅仅因为一次健康检查就包含额外的中间件吗?不,谢谢
您可以使用不同的协议,如TCP
总的想法是:
干杯 这会报告辅助服务的错误线程吗?我的意思是,由于未处理的异常和卡住,WorkService无法执行任务,而/HealthEndoPoT不认为它总是响应于200 OK,因为它在一起运行在不同的线程中。不,您必须以某种方式从健康检查中检测到服务停止响应。也许是工作人员的心跳,但即使如此,我也看到过不完全准确的情况。我认为这是在使用Kubernetes时不使用Microsoft.NET.Sdk.Web的最优雅的方法。您甚至可以打开两个不同的TCP端口,一个用于live,另一个用于ready端点。
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;
}
}