docs(kdoc): 其余模块注释统一为直白说明
把上一提交没覆盖到的模块也改完,至此仓库内不再有"只写编号、不写说明"的注释。 涉及 33 个文件(生产 24 + 测试 9),包括航班状态模型与合并引擎、事件与留痕模型、 运营日计算、投递器、历史归档作业、编解码与身份、重试与重放、健康指示器、 生命周期装配、以及各自的测试类。 改法与前面一致:先说这段代码做什么,再说为什么这么做,术语第一次出现就地解释 (FLID、OPERATION_DAY、航班版本号、删除通知、待发事件表等)。工单编号 (U07/N02/ACM2-10 之类)已全部移除;段落编号只剩 10 处,全部带文件名位于句尾, 用作延伸阅读,例如"见 docs/flight-state.md §5"。 保留了本来就自解释的行内注释、PgTestSupport 顶部的环境变量默认值表格, 以及 InboxController 里描述待补接口的 TODO。 校验:逐文件做"去注释后比对"(块注释 + 行注释清除、空白归一),33 个文件代码 零差异;另做逐行非注释代码比对,同样零差异。clean test 为 78 passed / 1 skipped。
This commit is contained in:
@@ -10,11 +10,13 @@ import jakarta.inject.Singleton
|
||||
import org.reactivestreams.Publisher
|
||||
|
||||
/**
|
||||
* U12(R05):自定义健康指示器——
|
||||
* Kafka(投递端口)。经 BeanProvider 可选解析:
|
||||
* 缺 bean(如未用 stub 也未实装)时指示 DOWN 而非启动失败;
|
||||
* UP 判据为真实 ping(false/异常 → DOWN),而非仅 bean 存在(复审 P1 修正)。
|
||||
* (ACM2-28:Redis 退出阶段 A 权威与写路径,redis-flight-store 指示器移除)。
|
||||
* 把 Kafka 投递端口的状态报给 /health。
|
||||
*
|
||||
* 用 BeanProvider 可选注入:没配 stub、也还没有真实实现时,端口 bean 根本不存在,这时报 DOWN
|
||||
* 而不是让服务起不来。判 UP 的依据是真的调一次 ping——返回 false 或抛异常都算 DOWN,
|
||||
* 不是"bean 在就算好"。
|
||||
*
|
||||
* Redis 已经不再参与航班状态的写入和判定,对应的健康指示器也一并删掉了。
|
||||
*/
|
||||
@Singleton
|
||||
class KafkaDeliveryHealthIndicator(
|
||||
|
||||
@@ -3,8 +3,8 @@ package com.gzzn.omms.msgexchange.infra.log
|
||||
import org.slf4j.MDC
|
||||
|
||||
/**
|
||||
* U12(R05):处理路径入口写入 MDC traceId(=cminmsgsId/eventId),
|
||||
* 使一条消息全链路日志可串(logback %X{traceId} + logstash includeMdcKeyName)。
|
||||
* 处理一条消息时把它的 ID(信箱 ID 或事件 ID)放进 MDC 的 traceId,用 withTrace 把整段处理
|
||||
* 逻辑包起来;日志配置里带上 %X{traceId},同一条消息的日志就能串到一起。
|
||||
*/
|
||||
object TraceLog {
|
||||
fun <T> withTrace(id: Any, body: () -> T): T {
|
||||
|
||||
@@ -233,7 +233,10 @@ interface ReqTrackRepository {
|
||||
|
||||
fun findLatest(reqType: String, operationDay: LocalDate, sender: String, states: List<ReqState>): Req?
|
||||
|
||||
/** RESP 完成请求(design.md §4.2):匹配最新一条 PENDING/SENT;无匹配返回 false(迟到不报错)。 */
|
||||
/**
|
||||
* 应答报文到达时把对应请求标记为已完成:匹配最近一条待应答的请求(PENDING 或 SENT)。
|
||||
* 找不到返回 false——迟到或多余的应答不算错误。
|
||||
*/
|
||||
fun completeLatest(reqType: String, operationDay: LocalDate, sender: String): Boolean
|
||||
|
||||
fun linkCoutmsgs(reqId: Long, coutmsgsId: Long)
|
||||
|
||||
@@ -7,28 +7,29 @@ import java.time.Clock
|
||||
import java.time.Instant
|
||||
|
||||
/**
|
||||
* 统一重试策略(ACM2-10 U08):供 MessageProcessor / SnapshotFlow(ProcState 侧)与
|
||||
* Dispatcher(MsgEvent 侧)共用——attempts 递增后按 backoff 表给 nextAttemptAt;
|
||||
* exhausted 判定与两侧同源(maxAttempts)。时间一律经可注入 Clock(测试用固定钟,避免脆弱睡眠)。
|
||||
* 重试节奏的唯一出处:处理失败的入站消息和待发事件都用它算下次重试时间,保证两边口径一致。
|
||||
*
|
||||
* 重试次数加一之后,按退避表算出下次可以重试的时刻;"次数是否已经用尽"也在这里判断,
|
||||
* 上限取 msgx.pipeline.max-attempts。时间一律走注入的 Clock,测试可以塞固定时钟,不用 sleep。
|
||||
*/
|
||||
@Singleton
|
||||
class FailureScheduler(
|
||||
private val props: PipelineProps,
|
||||
private val clock: Clock,
|
||||
) {
|
||||
/** 便捷构造:默认系统时钟(生产路径)。 */
|
||||
/** 生产环境用这个构造:时钟取系统 UTC 时间。 */
|
||||
constructor(props: PipelineProps) : this(props, Clock.systemUTC())
|
||||
|
||||
fun now(): Instant = clock.instant()
|
||||
|
||||
fun exhausted(attempts: Int): Boolean = attempts >= props.pipeline.maxAttempts
|
||||
|
||||
/** attempts 指递增后的值;N28:attempt ≤ 0 由 backoffFor 兜底为首档。 */
|
||||
/** 传入的 attempts 是已经加一之后的值。若传 0 或负数(比如 FAILED 行还没记过次数),退避表会兜底给第一档。 */
|
||||
fun nextAttemptAt(attemptsAfterIncrement: Int): Instant =
|
||||
now().plusMillis(props.pipeline.backoffFor(attemptsAfterIncrement))
|
||||
}
|
||||
|
||||
/** 提供可注入 Clock(java.time.Clock);测试可用 Clock.fixed(...) 或自定义可变钟覆盖。 */
|
||||
/** 把 Clock 注册成可注入的 bean;测试里可以换成 Clock.fixed(...) 或自己写的可推进时钟。 */
|
||||
@Factory
|
||||
class TimeFactory {
|
||||
@Singleton
|
||||
|
||||
@@ -5,19 +5,21 @@ import com.gzzn.omms.msgexchange.infra.persistence.ProcStateRepository
|
||||
import jakarta.inject.Singleton
|
||||
|
||||
/**
|
||||
* U11 显式重放入口:只允许“可恢复”的错误类从 FAILED/DEAD 回到 PENDING(主泵重领)。
|
||||
* 不可恢复类(MALFORMED——报文非法,重放必再失败)与未知类一律不在白名单内。
|
||||
* 人工重放入口:把失败的消息从 FAILED/DEAD 拨回 PENDING,让主泵重新领走处理。
|
||||
*
|
||||
* 只有"再试一次有可能成功"的错误类才放行。报文本身不合法的(MALFORMED)重放多少次都一样,
|
||||
* 所以不在白名单里;没列出的错误类也一律不放行。
|
||||
*/
|
||||
@Singleton
|
||||
class ReplayService(
|
||||
private val procState: ProcStateRepository,
|
||||
) {
|
||||
private val log = org.slf4j.LoggerFactory.getLogger(ReplayService::class.java)
|
||||
/** 可恢复错误类:codec 修复可重放 / 未实装补齐可重放 / 基础设施抖动可重放 / 重试耗尽后人工复核可重放。 */
|
||||
/** 可以重放的错误类:解码逻辑修好后能过、处理器补齐后能过、基础设施抖动已恢复、以及重试耗尽但人工复核认为还能再试的。 */
|
||||
val replayableErrorClasses: Set<ErrorClass> =
|
||||
setOf(ErrorClass.CODEC_ERROR, ErrorClass.UNSUPPORTED, ErrorClass.INFRA, ErrorClass.EXHAUSTED)
|
||||
|
||||
/** 只重放白名单内的类;请求含 MALFORMED 等非法类时静默忽略该类。 */
|
||||
/** 只放行白名单内的错误类;请求里带了 MALFORMED 这类不可重放的,直接忽略不报错。 */
|
||||
fun replay(requested: Collection<ErrorClass>): Int {
|
||||
val allowed = requested.filter { it in replayableErrorClasses }
|
||||
if (allowed.isEmpty()) {
|
||||
@@ -29,6 +31,6 @@ class ReplayService(
|
||||
return n
|
||||
}
|
||||
|
||||
/** 默认入口:重放全部可恢复类。 */
|
||||
/** 什么都不指定时走这个:把白名单里的错误类全部重放一遍。 */
|
||||
fun replayAll(): Int = replay(replayableErrorClasses)
|
||||
}
|
||||
|
||||
@@ -5,8 +5,10 @@ import io.micronaut.context.annotation.Requires
|
||||
import jakarta.inject.Singleton
|
||||
|
||||
/**
|
||||
* stub 适配层——DeliveryPort 内存实现,仅在 msgx.stubs=true 时生效。
|
||||
* 记录 (topic, key, payload):payload = null 表示 TOMBSTONE(flight-state.md §5 键缺失=删除旧值)。
|
||||
* 投递端口的内存假实现,只有配置 msgx.stubs=true 时才装配,本地开发和测试用。
|
||||
*
|
||||
* 每次发送都往 sent 里记一条(topic、key、payload);payload 为 null 的那条就是删除通知
|
||||
* (tombstone,下游按"这个键没了"理解成删除)。见 docs/flight-state.md §5。
|
||||
*/
|
||||
@Requires(property = "msgx.stubs", value = "true")
|
||||
@Singleton
|
||||
|
||||
Reference in New Issue
Block a user