fix(processing): 收紧消息生命周期与投递约束
This commit is contained in:
@@ -2,7 +2,9 @@ package com.gzzn.omms.msgexchange.processing
|
||||
|
||||
import com.gzzn.omms.msgexchange.config.MailboxProps
|
||||
import com.gzzn.omms.msgexchange.config.PipelineProps
|
||||
import com.gzzn.omms.msgexchange.domain.ProcStatus
|
||||
import com.gzzn.omms.msgexchange.infra.persistence.CminmsgInboxRepository
|
||||
import com.gzzn.omms.msgexchange.infra.persistence.MailboxMarkResult
|
||||
import com.gzzn.omms.msgexchange.infra.persistence.ProcStateRepository
|
||||
import jakarta.inject.Singleton
|
||||
import java.time.Clock
|
||||
@@ -32,12 +34,14 @@ class BackfillService(
|
||||
private val mailboxProps: MailboxProps,
|
||||
private val props: PipelineProps,
|
||||
private val clock: Clock,
|
||||
private val lifecycleGate: MessageLifecycleGate = MessageLifecycleGate(),
|
||||
) {
|
||||
private val log = org.slf4j.LoggerFactory.getLogger(BackfillService::class.java)
|
||||
|
||||
companion object {
|
||||
private val INITIAL_BACKOFF: Duration = Duration.ofSeconds(30)
|
||||
private val MAX_BACKOFF: Duration = Duration.ofMinutes(15)
|
||||
private val TERMINAL_STATES = setOf(ProcStatus.SUCCEEDED, ProcStatus.SKIPPED, ProcStatus.DEAD)
|
||||
|
||||
fun backoffDelayFor(attempts: Int): Duration {
|
||||
val shift = (attempts - 1).coerceIn(0, 20)
|
||||
@@ -50,8 +54,13 @@ class BackfillService(
|
||||
* 调用方是主泵的处理路径,不能被回填问题拖住。
|
||||
*/
|
||||
fun attempt(msgId: Long, now: Instant = clock.instant()) {
|
||||
record(msgId, attempts = 0, now = now)?.let {
|
||||
log.warn("backfill failed msgId={} error={} (sweep will retry)", msgId, it)
|
||||
lifecycleGate.exclusive {
|
||||
val row = procState.find(msgId) ?: return@exclusive
|
||||
if (row.state !in TERMINAL_STATES) return@exclusive
|
||||
if (row.backfillAt != null) return@exclusive
|
||||
record(msgId, attempts = row.backfillAttempts, now = now)?.let {
|
||||
log.warn("backfill failed msgId={} error={} (sweep will retry)", msgId, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +71,7 @@ class BackfillService(
|
||||
*/
|
||||
fun sweep(now: Instant = clock.instant()): Int {
|
||||
val due = procState.findBackfillDue(now, now.minus(props.pipeline.overdueBackfill), props.pipeline.backfillBatch)
|
||||
due.forEach { record(it.msgId, it.attempts, now) }
|
||||
due.forEach { attempt(it.msgId, now) }
|
||||
return due.size
|
||||
}
|
||||
|
||||
@@ -70,7 +79,8 @@ class BackfillService(
|
||||
private fun record(msgId: Long, attempts: Int, now: Instant): String? =
|
||||
try {
|
||||
// 没有真正写进去说明库里已经有标记了,同样算成功(不覆盖已有值)
|
||||
mailbox.markProcessedIfUnmarked(msgId, mailboxProps.processedValue)
|
||||
val result = mailbox.markProcessedIfUnmarked(msgId, mailboxProps.processedValue)
|
||||
check(result != MailboxMarkResult.MISSING) { "mailbox-row-missing" }
|
||||
procState.markBackfilled(msgId, now)
|
||||
null
|
||||
} catch (e: Exception) {
|
||||
@@ -80,4 +90,5 @@ class BackfillService(
|
||||
}.onFailure { log.error("record backfill failure failed msgId={}", msgId, it) }
|
||||
reason
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user