feat(outbound): REQ_TRACK/COUTMSGS/schd-sync 与 RESP 守卫(ACM2-92/86)
出站请求状态机与编码;SCHD-RESP 须匹配未过期开放请求;EROR 结案匹配 SENT。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
package com.gzzn.omms.msgexchange.processing
|
||||
|
||||
import com.gzzn.omms.msgexchange.codec.ErorPayload
|
||||
import com.gzzn.omms.msgexchange.codec.FlopPayload
|
||||
import com.gzzn.omms.msgexchange.codec.ScheduleBody
|
||||
import com.gzzn.omms.msgexchange.codec.XmlCodec
|
||||
@@ -123,6 +124,7 @@ class MessageProcessor(
|
||||
private val flopProcessor: FlopProcessor,
|
||||
private val fdelProcessor: FdelProcessor,
|
||||
private val adftProcessor: AdftProcessor,
|
||||
private val outbound: OutboundRequestService,
|
||||
private val procFailure: ProcFailure,
|
||||
private val props: PipelineProps,
|
||||
private val clock: Clock,
|
||||
@@ -201,8 +203,24 @@ class MessageProcessor(
|
||||
val body = decoded.body as? ScheduleBody
|
||||
if (body == null) return deadMalformed(head, "missing-schd-body")
|
||||
when (kind.subtype) {
|
||||
MsgKind.SchdSubtype.DNLD, MsgKind.SchdSubtype.RESP ->
|
||||
MsgKind.SchdSubtype.DNLD ->
|
||||
scheduleProcessor.applyScheduleRecords(head, decoded)
|
||||
MsgKind.SchdSubtype.RESP -> {
|
||||
if (!outbound.hasOpenSentRqfd()) {
|
||||
log.info("SCHD-RESP without open RQFD -> SKIPPED msgId={} [G-RESP-GUARD]", head.msgId)
|
||||
procState.markTerminal(
|
||||
head.msgId, ProcStatus.SKIPPED,
|
||||
lastError = "resp-guard:no-open-req",
|
||||
now = clock.instant(),
|
||||
)
|
||||
return
|
||||
}
|
||||
val respResult = scheduleProcessor.applyScheduleRecords(head, decoded)
|
||||
if (respResult is ApplyResult.Succeeded || respResult is ApplyResult.ReplaySkipped) {
|
||||
outbound.completeRqfdResponse()
|
||||
}
|
||||
respResult
|
||||
}
|
||||
MsgKind.SchdSubtype.ADFT -> {
|
||||
val record = body.records.singleOrNull()
|
||||
if (record == null) return deadMalformed(head, "adft-needs-single-fltr")
|
||||
@@ -227,9 +245,20 @@ class MessageProcessor(
|
||||
return procFailure.fail(head, ErrorClass.UNSUPPORTED, "refdata-pending:${kind.type}")
|
||||
}
|
||||
MsgKind.Eror -> {
|
||||
// US-09 AC3:须匹配出站请求;REQ_TRACK 协调器落地前(ACM2-92)先按可重试失败留队。
|
||||
log.warn("eror without handler -> FAILED(UNSUPPORTED) msgId={}", head.msgId)
|
||||
return procFailure.fail(head, ErrorClass.UNSUPPORTED, "eror-pending")
|
||||
val payload = decoded.body as? ErorPayload
|
||||
?: return deadMalformed(head, "missing-eror-body")
|
||||
val matched = outbound.failFromEror(payload.seqs, payload.typs, payload.stys)
|
||||
if (!matched) {
|
||||
log.info("EROR without matching open outbound -> SKIPPED msgId={}", head.msgId)
|
||||
procState.markTerminal(
|
||||
head.msgId, ProcStatus.SKIPPED,
|
||||
lastError = "eror:no-matching-req",
|
||||
now = clock.instant(),
|
||||
)
|
||||
} else {
|
||||
procState.markTerminal(head.msgId, ProcStatus.SUCCEEDED, now = clock.instant())
|
||||
}
|
||||
return
|
||||
}
|
||||
is MsgKind.Unsupported -> {
|
||||
// 合法但不支持的类型:跳过留档记 SKIPPED(US-03 AC2;markTerminal 同一条 UPDATE
|
||||
|
||||
Reference in New Issue
Block a user