Skip to content

健康检查中间件

健康检查中间件用于实时监控应用及其依赖(如数据库、缓存、外部服务等)的运行状态,便于自动化运维和故障告警。

使用中间件

我们可以使用中间件来运行检查项。

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
}