feat(config): 配置值非法无条件拒启,登记启动必需配置清单(ACM2-97)

- 新增 PipelineConfigCheck(@Context):退避档位/播种取值校验不再等 autostart(CLM-7、OPS-1)
- OperationDayZoneCheck 扩展 cutoff-hour 0-23 校验
- reference.md 新增「启动必需配置与显式开关」:必需清单、缺值路径、显式开关与运行时故障的边界
- PipelinePropsBindingTest 补一致退避档位;补非法值/范围用例
This commit is contained in:
windyboy
2026-09-21 12:46:47 +08:00
parent 9bf879ff76
commit 477f038cc1
7 changed files with 89 additions and 7 deletions
@@ -1,6 +1,5 @@
package com.gzzn.omms.msgexchange
import com.gzzn.omms.msgexchange.config.PipelineProps
import com.gzzn.omms.msgexchange.delivery.Dispatcher
import com.gzzn.omms.msgexchange.ingress.InboxPoller
import com.gzzn.omms.msgexchange.processing.Pump
@@ -25,7 +24,6 @@ class PipelineLifecycle(
private val pump: Pump,
private val dispatcher: Dispatcher,
private val jobRunner: JobRunner,
private val props: PipelineProps,
) {
private val log = org.slf4j.LoggerFactory.getLogger(PipelineLifecycle::class.java)
private val threads = mutableListOf<Thread>()
@@ -40,9 +38,8 @@ class PipelineLifecycle(
private fun startIfNeeded() {
if (started) return
// 自检放在起线程之前:配置错位(例如退避表档位数与 max-attempts 不匹配、
// 有一段退避永远走不到)必须让启动失败,而不是静默按错误参数长期运行
props.pipeline.validate()
// 管道参数合法性已由 PipelineConfigCheck 在启动时无条件校验(CLM-7);
// 这里只负责拉起循环线程
started = true
threads += spawn("msgx-inbox-poller", poller::loop)
threads += spawn("msgx-pump", pump::loop)
@@ -32,9 +32,14 @@ class OperationDayProps {
}
}
/** 启动自检:时区非法必须在启动时失败,而不是等第一条报文进来才炸;`@Context` 使其急切创建。 */
/** 启动自检:时区或切日边界非法必须在启动时失败,而不是等第一条报文进来才炸;`@Context` 使其急切创建。 */
@Singleton
@Context
class OperationDayZoneCheck(props: OperationDayProps) {
private val zone: ZoneId = props.zoneId()
init {
props.zoneId()
require(props.cutoffHour in 0..23) {
"msgx.operation-day.cutoff-hour must be 0-23, got ${props.cutoffHour}"
}
}
}
@@ -0,0 +1,17 @@
package com.gzzn.omms.msgexchange.config
import io.micronaut.context.annotation.Context
import jakarta.inject.Singleton
/**
* 管道参数启动自检:退避表档位数与 `max-attempts` 的匹配、切流播种取值等,
* 值非法时拒绝启动。无条件执行(`CLM-7`)——不再等 `msgx.pipeline.autostart=true`
* 才校验:配置值本身非法与依赖是否接入无关,静默放行会让错误参数在开启时才爆出来。
*/
@Singleton
@Context
class PipelineConfigCheck(props: PipelineProps) {
init {
props.pipeline.validate()
}
}