🔭可观测性与降级
版本支持:v2.16.1+
Rule-DB运行时会暴露一个只读的结构快照RuleDbRuntimeSnapshot,里面不含规则和脚本全文,用来观测同步进度、定位加载失败的目标。
# Spring Boot:actuator端点
两个LiteFlow starter都已经传递了liteflow-metrics,但Spring Boot Actuator在starter里是optional依赖,所以应用要自己显式引入:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
然后把liteflow端点暴露出来:
management.endpoints.web.exposure.include=health,info,liteflow
之后就能访问了:
GET /actuator/liteflow/ruledb
返回的JSON大致是这样(节选):
{
"active": true,
"provider": "sql",
"changeSource": {
"status": "UP",
"recentError": null,
"lastSuccessTime": 1720000000000,
"cursor": 128
},
"lastAppliedSeq": 128,
"lastSuccessfulReconcileTime": 1720000060000,
"lastReconcileError": null,
"targets": {
"shadow": 2, "ready": 48, "stale": 1,
"loading": 0, "failed": 1, "deleted": 0
},
"failedTargets": [
{ "targetType": "chain", "targetId": "brokenChain",
"status": "FAILED", "desiredVersion": 5, "activeVersion": 4,
"error": "fetch chain[brokenChain] failed after 3 retries: ..." }
]
}
几个字段的含义。
changeSource.status是变更通道的健康度:
| 值 | 含义 |
|---|---|
UP | 正常 |
DEGRADED | 最近一次轮询或watch报错了,但还在重试 |
DOWN | 已关闭 |
STARTING | 还没激活 |
targets是所有chain和script按生命周期状态的计数:
| 状态 | 含义 |
|---|---|
shadow | 索引已登记,内容还没加载,也就是冷态 |
loading | 正在回源加载 |
ready | 已加载,且和权威版本一致,这是正常态 |
stale | 权威版本变了,本地还没刷新到期望版本 |
failed | 加载失败,明细看failedTargets |
deleted | 已经从权威源删除,等待清理 |
failedTargets是处于failed状态的目标明细,最多20条,带上期望版本、当前已激活版本和错误信息。activeVersion大于0说明还有last-good generation在服务,等于0才说明没有可回退的成功版本。
提示
这个端点由liteflow-metrics里的LiteflowMetaView提供。同一个端点下还有/actuator/liteflow/chains、/actuator/liteflow/nodes之类的结构检视能力,详见指标监控。
# 非Spring或没有actuator的环境
直接调com.yomahub.liteflow.repository.RuleDbRuntime.snapshot()就能拿到同一个RuleDbRuntimeSnapshot对象,你自己序列化或者对接监控都可以。Solon环境没有自动的actuator,也用这个方式。
# 降级语义
存储出故障时,Rule-DB的行为边界是明确的:
| 故障场景 | 行为 |
|---|---|
| 启动时存储不可用 | FlowExecutor初始化阶段拉取manifest失败会直接抛异常、启动失败,不会降级成空规则先跑起来。Rule-DB模式的启动是强依赖存储可用的。 |
| 运行期存储不可用,但已有成功激活的版本 | 照常执行last-good generation。即使已经感知到更高的期望版本,只要旧版还是已激活版本,新版回源失败也不会先把旧版销毁。运行时会记一个FAILED,后续执行继续尝试新版。 |
| 运行期存储不可用,且没有已激活版本 | fetch会按fetch-retry-times(默认3次)重试,仍然失败就抛ChainLoadException。它和ChainNotFoundException的区别是,前者是规则存在但取不回来,后者是规则不存在。存储恢复之后下次执行会自动回源,不用人工干预。 |
| 变更通道故障,比如轮询报错、watch或Listener断线 | 标记成DEGRADED并重试。SQL、PostgreSQL、MongoDB、Redis轮询失败会在下个周期重试;zk和etcd断线后重建监听并触发全量对账;Nacos的监听由客户端维护,回调损坏、序号断档或消费失败时会请求全量对账。断线这段窗口由周期对账兜底。 |
| change_log或changelog被清理、损坏 | SQL和PostgreSQL的seq是全表自增序号,不同application_name之间跳号是正常的。水位已经前进但读不到本应用记录时会请求对账,其他被裁剪掉的历史主要靠周期对账补齐。MongoDB和Redis用的是连续的应用级序号,可以直接检测断档。Nacos只保留连续的sequence和最后一条变更,序号断档或内容损坏会请求全量对账。 |
| fetch到enable=false,或者行、节点不存在 | 如果已有激活版本,这次候选加载失败仍然保留last-good;如果没有激活版本则抛ChainLoadException。之后对账确认目标确实已删除,会把它从索引和FlowBus里移除,再执行时就按chain不存在处理。 |
| 变更已感知,但回源或编译新版失败 | 如果存在已激活版本,记一个FAILED,保留旧的activeVersion继续执行,之后每次执行都继续尝试desiredVersion。如果从来没成功激活过任何版本,那这次执行抛ChainLoadException。chain和脚本的语义是一样的。 |
SQL缺表,且没开auto-init-table | 首次访问存储时报ConfigErrorException,错误信息里带完整的DDL,可以直接复制执行。 |
一句话总结:已成功激活的last-good generation是普通升级失败时的可用性下限。但冷规则的首次加载、显式删除、删除后重建以及缓存淘汰,都不要理解成会永久保留旧版。



