如何为 Grails 正确实施负载均衡器健康检查

How to properly implement load balancer healthcheck for Grails

我正在使用部署到使用软件负载平衡器 (ELB) 的 Amazon AWS 的 Grails 2 应用程序。我们遇到的问题是在应用程序完全初始化之前将 grails 应用程序实例添加到负载均衡器。它是 resources 插件,专门为 javascript、css、图像等静态资产提供服务

负载均衡器向 'healthcheck' URL 发出 http 请求。 GET '/myapp/lbcheck'

LoadBalancerController.groovy:

package myapp

class LoadBalancerController {

    def healthService

    def healthcheck() {
        response.contentType = 'text/plain'
        try {
            healthService.checkDatabase()
            render(status: 200, text: "Up")
        }
        catch(Exception ex) {
            log.error("Error with database healthcheck " + ex)
            render(status: 503, text: "Down")
        }
    }
}

HealthSerivce.groovy

package myapp

import groovy.sql.Sql

class HealthService {

    def dataSource

    // Either returns true, or throws an Exception
    def checkDatabase() {
        Sql sql = new Sql(dataSource)
        sql.rows("SELECT 429")
        sql.close()
        return true
    }
}

SQL 查询显然是不够的。看来我们需要在框架中检查一些其他类型的 属性 以确定它是否已被初始化。

您可以尝试在 BootStrap.groovy 中将 healthService bean 上的字段设置为 true。我认为那是在 Grails 完全初始化之后 运行。

package myapp

import groovy.sql.Sql

class HealthService {

    def dataSource

    def initializationComplete = false

    // Either returns true, or throws an Exception
    def checkDatabase() {
        Sql sql = new Sql(dataSource)
        sql.rows("SELECT 429")
        sql.close()
        return true
    }
}

里面 BootStrap.groovy:

class BootStrap {
    def healthService

    def init = { servletContext ->
        healthService.initializationComplete = true
    }

}

在你的 LoadBalancerController.groovy:

def healthcheck() {
    response.contentType = 'text/plain'
    def healthy = false
    try {
        healthy = healthService.with { 
            initializationComplete && checkDatabase()
        }
    }
    catch(Exception ex) {
        log.error("Error with database healthcheck " + ex)
    }

    if (healthy) {
        render(status: 200, text: "Up")
    } else {
        render(status: 503, text: "Down")
    }
}