应新建独立的HealthController:在app/controllers/下创建health.go,仅嵌入*revel.Controller,实现无钩子的Get()方法,注册GET /health路由,验证DB Ping和Redis连接,超时2秒内返回503,且路由注册需置于filter.go所有Filter之前以绕过Filter链。

健康检查该放在哪个Controller里
Revel 没有内置 /health 路由,也不能塞进 UserController 或 AppController 里——这会让探针逻辑和业务耦合,Kubernetes 的 livenessProbe 一旦被中间件(比如 JWT 鉴权、日志记录)拦截或拖慢,容器就会反复重启。
正确做法是新建一个独立的 HealthController:
- 在
app/controllers/下新建health.go - 结构体只嵌入
*revel.Controller,不继承任何业务基类 - 仅实现
Get()方法,不带任何Before()/After()钩子 - 在
routes文件中用最简方式注册:GET /health HealthController.Get
返回什么才算真正“健康”
只写 this.RenderText("OK") 是假健康。进程活着 ≠ 服务可用。真实场景下必须验证关键依赖是否就绪,但又不能拖慢探针本身。
实操建议:
- 数据库:用
revel.BEANSTALK_DB(或你配置的 DB 实例)调db.PingContext(ctx),设context.WithTimeout(ctx, 2*time.Second) - Redis 缓存:若用了
revel.Cache,调revel.Cache.IsConnected()(需提前在conf/app.conf中配好cache.redis) - 跳过耗时操作:不读大文件、不调外部 HTTP、不查全表 —— 这些留给
readinessProbe做 - 失败时直接
this.Abort(503),别吞错、别重定向、别渲染模板
怎么绕过 Revel 的 Filter 链
Revel 默认所有路由都走完整 Filter 链(RouterFilter → SessionFilter → InterceptorFilter → ... → ActionInvoker)。但健康接口不该被 JWTFilter 拦、不该被 LogFilter 记慢日志、更不该被 ValidationFilter 解析参数。
两个可靠方案:
-
推荐:把
GET /health路由注册语句,放在filter.go中所有revel.Intercept()和revel.FILTERS = append(...)之前 —— 这样它根本不会进入 Filter 链 - 备选:在鉴权类 Filter 里加白名单判断:
if strings.HasPrefix(c.Request.URL.Path, "/health") { return } - 确认没开
revel.BConfig.WebConfig.DisableStatic = false(静态文件中间件不影响 API,但误配可能干扰路径匹配)
Kubernetes 探针配置的关键参数
Revel 的 /health 是给 livenessProbe 用的,不是 readinessProbe。二者目标不同,配置不能混用。
生产环境推荐值(来自 CNCF 实践共识):
-
initialDelaySeconds: 10—— 容器启动后等 10 秒再开始探,避开 Revel 初始化 DB 连接池、加载配置的窗口期 -
periodSeconds: 5—— 每 5 秒探一次,太密增加负载,太疏延迟故障发现 -
timeoutSeconds: 2—— 单次请求超时设为 2 秒,避免因网络抖动或 DB 短暂卡顿误判 -
failureThreshold: 3—— 连续失败 3 次才触发重启,容忍瞬时抖动
注意:不要在 livenessProbe 里检查 Redis 写入或远程 HTTP —— 这类操作失败应走 readinessProbe 下线流量,而不是杀进程。


















