docs(acm2-75): 重排 Q 序号并补齐 Redis 投影与查询侧边界
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -85,7 +85,7 @@ class JacksonXmlCodec : XmlCodec {
|
||||
/**
|
||||
* 子类型分派必须是**白名单**:未知的 SCHD 子类型不能静默当成全量日计划(DNLD)——
|
||||
* 那会让一条本该"暂不支持、等人工处置"的报文走最重的整包合并写入路径。
|
||||
* 空 STYP 按 legacy 约定视为 DNLD(该约定待与 SIS 逐类对拍确认,见 Q8)。
|
||||
* 空 STYP 按 legacy 约定视为 DNLD(该约定待与 SIS 逐类对拍确认,见 Q3)。
|
||||
*/
|
||||
private fun kindOf(type: String, styp: String): MsgKind = when (type) {
|
||||
"SCHD" -> when (styp) {
|
||||
|
||||
@@ -23,7 +23,7 @@ data class ScheduleBody(
|
||||
* 只保留在 wire/domain、尚未映射到持久化明细的集合键(`[G-SRVT-VIPF]`)。
|
||||
*
|
||||
* 它们不参与合并、不进快照、不落库;保留的目的是不让入站事实在解码层被静默抹平,并让真实
|
||||
* 流量里的出现情况可观测——决定"缺席是否等于删除"的 `Q13` 需要真实报文才能定案。
|
||||
* 流量里的出现情况可观测——决定"缺席是否等于删除"的 `Q11` 需要真实报文才能定案。
|
||||
*/
|
||||
private val UNPERSISTED_COLLECTION_KEYS: Set<String> = setOf("SRVT", "VIPF")
|
||||
|
||||
@@ -132,7 +132,7 @@ data class FlightRecordXml(
|
||||
@param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "ROUT") val rout: List<RoutXml> = emptyList(),
|
||||
@param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "ERUT") val erut: List<RoutXml> = emptyList(),
|
||||
// SRVT/VIPF 用可空表达"段是否出现":null = 未出现;出现即为列表(空元素得到一行空行)。
|
||||
// 两者都不落明细表、不参与合并,清空语义待 `Q13`(`[G-SRVT-VIPF]`)。
|
||||
// 两者都不落明细表、不参与合并,清空语义待 `Q11`(`[G-SRVT-VIPF]`)。
|
||||
@param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "SRVT") val srvt: List<SrvtXml>? = null,
|
||||
@param:JacksonXmlElementWrapper(useWrapping = false) @param:JacksonXmlProperty(localName = "VIPF") val vipf: List<VipfXml>? = null,
|
||||
)
|
||||
|
||||
@@ -38,7 +38,7 @@ internal object SisWireMapper {
|
||||
* `filterValues` 去掉的正是"缺席",避免整包凭空清空本地明细(合并语义见 docs/implementation.md「SCHD 日计划」)。
|
||||
*
|
||||
* `SRVT`/`VIPF` 尚未有明细表(`[G-SRVT-VIPF]`):只用"键是否存在"表达段是否出现,保留原始
|
||||
* 内容与顺序,不参与合并、不判断清空语义(`Q13`)——出现(哪怕为空)与缺席不再被抹平。
|
||||
* 内容与顺序,不参与合并、不判断清空语义(`Q11`)——出现(哪怕为空)与缺席不再被抹平。
|
||||
*/
|
||||
private fun FlightRecordXml.collections(): Map<String, List<Map<String, String>>> {
|
||||
val mapped = linkedMapOf(
|
||||
|
||||
@@ -21,7 +21,7 @@ class PipelineCounters {
|
||||
* 入站记录里出现 `SRVT`/`VIPF` 段的条数(`[G-SRVT-VIPF]`)。
|
||||
*
|
||||
* 这两个集合目前只保留在 wire/domain,不落明细表、不参与合并;计数是"真实报文有没
|
||||
* 有在用"的唯一取证渠道(清空语义 `Q13` 需要真实样例才能定案)。> 0 表示确有流量携带该段。
|
||||
* 有在用"的唯一取证渠道(清空语义 `Q11` 需要真实样例才能定案)。> 0 表示确有流量携带该段。
|
||||
*/
|
||||
fun unpersistedCollectionSeenAdd(hits: Map<String, Int>) {
|
||||
hits["SRVT"]?.let { srvtSeen.addAndGet(it.toLong()) }
|
||||
|
||||
@@ -94,7 +94,7 @@ class PipelineMetrics(
|
||||
.strongReference(true)
|
||||
.register(registry)
|
||||
|
||||
// SRVT/VIPF 尚未落明细表([G-SRVT-VIPF]):计数替代静默丢弃,为 Q13 提供真实流量证据。
|
||||
// SRVT/VIPF 尚未落明细表([G-SRVT-VIPF]):计数替代静默丢弃,为 Q11 提供真实流量证据。
|
||||
Gauge.builder("msgx.pipeline.codec.srvt_seen.total", counters) { it.srvtSeenCount().toDouble() }
|
||||
.strongReference(true)
|
||||
.register(registry)
|
||||
|
||||
+2
-2
@@ -37,10 +37,10 @@ class JdbcCminmsgInboxRepository(
|
||||
}
|
||||
} catch (e: IllegalStateException) {
|
||||
// 只调整适配代码、不碰共享 Schema:把"取不到 generated key"变成可诊断错误,
|
||||
// 指出这是共享信箱 ID 生成方式的前提(C-14、Q7)。
|
||||
// 指出这是共享信箱 ID 生成方式的前提(C-14、Q8)。
|
||||
throw IllegalStateException(
|
||||
"shared mailbox insert returned no generated CMINMSGS_ID; " +
|
||||
"the CMINMSGS_ID column must be DB-generated (C-14, Q7)",
|
||||
"the CMINMSGS_ID column must be DB-generated (C-14, Q8)",
|
||||
e,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -190,7 +190,7 @@ class MessageProcessor(
|
||||
}
|
||||
}
|
||||
|
||||
// [G-SRVT-VIPF]:SRVT/VIPF 段只保留在解码载荷里,尚未落明细表(清空语义待 Q13)。
|
||||
// [G-SRVT-VIPF]:SRVT/VIPF 段只保留在解码载荷里,尚未落明细表(清空语义待 Q11)。
|
||||
// 计数 + 告警替代此前的静默丢弃;出现即证明真实报文携带该段,可作为定案依据。
|
||||
val unpersisted = unpersistedCollectionHits(decoded.body)
|
||||
if (unpersisted.isNotEmpty()) {
|
||||
|
||||
@@ -18,7 +18,7 @@ msgx:
|
||||
max-attempts: 5 # 处理/投递同值
|
||||
backoff-ms: [1000, 2000, 4000, 8000] # 指数退避;档位数必须 = max-attempts - 1(启动自检)
|
||||
backoff-cap-ms: 60000
|
||||
max-commit-delay: 5m # 空洞老化:W+1 空洞超过该时延判定为永久(Q2 最大提交时延)
|
||||
max-commit-delay: 5m # 空洞老化:W+1 空洞超过该时延判定为永久(Q7 最大提交时延)
|
||||
overdue-backfill: 30d # 超期补写期限 R:仅须 R ≤ R_keep;判据比较本地 ENQUEUED_AT(implementation.md「回填」)
|
||||
backfill-batch: 100 # 回填扫描单批条数
|
||||
backfill-max-attempts: 100 # 单行重试的告警阈值;放弃判据是 R 超期,不是次数(implementation.md「回填」)
|
||||
@@ -78,7 +78,7 @@ flyway:
|
||||
# 处理回填;出站写 COUTMSGS;不建表/schema,ACM2-12)。驱动/依赖与信箱适配层
|
||||
# (CminmsgMailbox/OutboxMailbox)随 U05 批次引入。
|
||||
mailbox:
|
||||
processed-value: PROCESSED # 处理标记写入值(C-5/Q7:值集与写权限以库方契约为准)
|
||||
processed-value: PROCESSED # 处理标记写入值(C-5/Q8:值集与写权限以库方契约为准)
|
||||
shared-mysql:
|
||||
enabled: false
|
||||
url: ${MSGX_MAILBOX_URL}
|
||||
|
||||
@@ -284,7 +284,7 @@ CREATE INDEX idx_flight_chock_flid ON FLIGHT_CHOCK_OP (FLID);
|
||||
CREATE TABLE MSG_EVENT (
|
||||
EVENT_ID BIGSERIAL PRIMARY KEY, -- 对 KAFKA:msg 是稳定事件身份并决定投递顺序;对 KAFKA:schd 是每次接受 upsert 时替换的写代次
|
||||
TARGET VARCHAR(30) NOT NULL, -- KAFKA:msg / KAFKA:schd
|
||||
PARTITION_KEY VARCHAR(32) NOT NULL, -- 当前恒为 FLID(Q4 定案前为假定,C-29)
|
||||
PARTITION_KEY VARCHAR(32) NOT NULL, -- 当前恒为 FLID(Q1 定案前为假定,C-29)
|
||||
EVENT_TYPE VARCHAR(16) NOT NULL DEFAULT 'UPSERT', -- UPSERT / TOMBSTONE
|
||||
STATE_VERSION BIGINT NOT NULL, -- 发布时航班版本;schd 聚合按 FLID 只进不退
|
||||
PAYLOAD_JSON TEXT NOT NULL, -- TOMBSTONE 时至少含 FLID/STATE_VERSION/DELETED
|
||||
|
||||
@@ -20,7 +20,7 @@ Flyway 配置**;PG 路径使用 `classpath:db/migration`,两者互不混用
|
||||
`NUMBER`/序列替代 `BIGSERIAL`、`TIMESTAMP WITH TIME ZONE`、`VARCHAR2` BYTE/CHAR 语义钉死。
|
||||
- `INSERT ... ON CONFLICT` 改 11g MERGE(OPERATION_DAY 不可变条件,`INV-12`)。
|
||||
- 空串按 NULL 的语义回归:显式清空的 presence 信息不得被 11g 空串语义吞掉
|
||||
(字段清空语义见 `Q13`;定案前按「未携带不清空」实现,`INV-14`)。
|
||||
(字段清空语义见 `Q11`;定案前按「未携带不清空」实现,`INV-14`)。
|
||||
- 11g 无部分索引:`uq_req_open` / `uq_schd_event` / `idx_proc_backfill_due` 三个带 `WHERE`
|
||||
的索引必须换成等价的函数索引或冗余列方案,不能照搬 PG 定义。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user