健康检查中间件
健康检查中间件用于实时监控应用及其依赖(如数据库、缓存、外部服务等)的运行状态,便于自动化运维和故障告警。
使用中间件
我们可以使用中间件来运行检查项。
cangjie
import spire_web_http.*
import spire_web_hosting.*
import spire_web_healthchecks.*
import spire_extensions_injection.*
import spire_extensions_healthchecks.*
main(args: Array<String>) {
let builder = WebHost.createBuilder(args)
builder.services.addHealthChecks()
.addCheck("h1", ["tcp"]) {
println("check: h1")
return HealthCheckResult.healthy()
}
let host = builder.build()
host.useHealthChecks("/health")
host.run()
return 0
}分组检查
我们可以根据检查项的特征进行分组,实践中我们可以对就绪和存活分别指定运行的检查项。
cangjie
main(args: Array<String>) {
let builder = WebHost.createBuilder(args)
builder.services.addHealthChecks()
.addCheck("h1", ["tcp"]) {
println("check: h1")
return HealthCheckResult.healthy()
}
.addCheck("h2", ["tcp"]) {
println("check: h2")
return HealthCheckResult.healthy()
}
.addCheck("s1", Duration.second * 3, ["sys"]) {
println("check: s1")
return HealthCheckResult.healthy()
}
let host = builder.build()
// 用于进行tcp检查
host.useHealthChecks("/health/tcp") {
options => options.predicate = {
c => c.tags.contains("tcp")
}
}
// 用于进行udp检查
host.useHealthChecks("/health/udp") {
options => options.predicate = {
c => c.tags.contains("udp")
}
}
host.run()
return 0
}IHealthCheck
我们可以实现IHealthCheck接口,来封装检查逻辑,并且支持依赖注入。
cangjie
main(args: Array<String>) {
let builder = WebHost.createBuilder(args)
builder.services.addHealthChecks()
.addCheck<MysqlHealthCheck>("mysql")
let host = builder.build()
host.useHealthChecks("/health")
host.run()
return 0
}
public class MysqlHealthCheck <: IHealthCheck {
// 允许依赖注入
public MysqlHealthCheck() {
}
public func check(context: HealthCheckContext): HealthCheckResult {
// 定义检查逻辑
return HealthCheckResult.healthy()
}
}超时机制
注册检查项时,我们可以指定超时时间。如果检查项运行超时,我们会发送超时信号,通知检查项尽快终止。
cangjie
main(args: Array<String>) {
let builder = WebHost.createBuilder(args)
builder.services.addHealthChecks()
.addCheck<MysqlHealthCheck>("mysql", Duration.second * 3)
let host = builder.build()
host.useHealthChecks("/health")
host.run()
return 0
}
public class MysqlHealthCheck <: IHealthCheck {
public func check(context: HealthCheckContext): HealthCheckResult {
// 超时我们会发送取消信号
while (!Thread.currentThread.hasPendingCancellation) {
println('checking...')
sleep(Duration.second)
}
println('canceled!')
return HealthCheckResult.healthy()
}
}自定义响应
cangjie
main(args: Array<String>) {
let builder = WebHost.createBuilder(args)
builder.services.addRouting()
builder.services.addHealthChecks()
.addCheck("mysql"){
sleep(Duration.second * 1)
HealthCheckResult.healthy()
}
.addCheck("pgsql"){
sleep(Duration.second * 2)
HealthCheckResult.healthy()
}
let host = builder.build()
host.useHealthChecks("/health") { options =>
options.responseWriter = { context, report =>
var msg = StringBuilder()
msg.append("<html><body>")
msg.append("status:${report.status.toString()},time:${report.totalDuration}<br/>")
msg.append("==============detail=================<br/>")
for ((name, entry) in report.entries) {
msg.append("${name}|${entry.duration}|${entry.status}<br/>")
}
msg.append("</body></html>")
context.response.addHeader(HeaderNames.ContentType, "text/html")
context.response.write(msg.toString())
}
}
host.run()
return 0
}html
<html>
<body>
status:Healthy,time:3s13ms<br/>
==============detail=================<br/>
mysql|1s9ms831us700ns|Healthy<br/>
pgsql|2s4ms72us200ns|Healthy<br/>
</body>
</html>使用终结点
我们也可以使用终结点来运行检查,框架对终结点做了大量的扩展,如跨域,身份认证等等。意味着我们可以对健康检查终结点进行保护。
cangjie
import spire_web_http.*
import spire_web_routing.*
import spire_web_hosting.*
import spire_web_healthchecks.*
import spire_extensions_injection.*
import spire_extensions_healthchecks.*
main(args: Array<String>) {
let builder = WebHost.createBuilder(args)
builder.services.addRouting()
builder.services.addHealthChecks()
.addCheck("mysql") {
HealthCheckResult.healthy()
}
let host = builder.build()
host.mapHealthChecks("/health")
//.requireAuthorization("JwtBearere") //请参考身份认证文档
host.run()
return 0
}