76 lines
2.5 KiB
Kotlin
76 lines
2.5 KiB
Kotlin
package com.gzzn.omms.msgexchange.jobs
|
|||
|
|
|
||
|
|
import com.gzzn.omms.msgexchange.config.HistoryProps
|
||
|
|
import com.gzzn.omms.msgexchange.config.PipelineProps
|
||
|
|
import jakarta.inject.Singleton
|
||
|
|
import java.time.Duration
|
||
|
|
import java.time.Instant
|
||
|
|
import java.time.LocalDate
|
||
|
|
import java.time.ZoneId
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 维护作业调度(docs/flight-state.md §8):单 daemon 线程,独立于主泵——
|
||
|
|
* 旧「作业不插队 PUMP_JOB 队列」机制随审计口径移除(§3.2 表清单无 PUMP_JOB);
|
||
|
|
* 历史归档/留痕清理均为内部清理路径,不参与 FIFO 消息序。
|
||
|
|
* 触发:回填补偿 30s 固定间隔;历史归档/留痕清理每日 03:30(机场时区)后首个 tick。
|
||
|
|
*/
|
||
|
|
@Singleton
|
||
|
|
class JobRunner(
|
||
|
|
private val backfillSweep: BackfillSweepJob,
|
||
|
|
private val historySweep: HistorySweepJob,
|
||
|
|
@Suppress("unused") private val pipelineProps: PipelineProps,
|
||
|
|
@Suppress("unused") private val historyProps: HistoryProps,
|
||
|
|
) {
|
||
|
|
private val log = org.slf4j.LoggerFactory.getLogger(JobRunner::class.java)
|
||
|
|
private val zone: ZoneId = ZoneId.of("Asia/Shanghai")
|
||
|
|
|
||
|
|
@Volatile
|
||
|
|
private var running = true
|
||
|
|
|
||
|
|
@Volatile
|
||
|
|
private var lastHistoryDay: LocalDate? = null
|
||
|
|
|
||
|
|
private var thread: Thread? = null
|
||
|
|
|
||
|
|
fun start() {
|
||
|
|
if (thread != null) return
|
||
|
|
running = true
|
||
|
|
thread = Thread.ofPlatform().name("msgx-jobs").daemon(true).start { loop() }
|
||
|
|
log.info("job runner started (backfill 30s, history daily 03:30 {})", zone)
|
||
|
|
}
|
||
|
|
|
||
|
|
fun stop() {
|
||
|
|
running = false
|
||
|
|
thread?.interrupt()
|
||
|
|
thread = null
|
||
|
|
}
|
||
|
|
|
||
|
|
internal fun loop() {
|
||
|
|
while (running) {
|
||
|
|
try {
|
||
|
|
backfillSweep.sweep()
|
||
|
|
maybeHistorySweep()
|
||
|
|
} catch (e: InterruptedException) {
|
||
|
|
Thread.currentThread().interrupt()
|
||
|
|
return
|
||
|
|
} catch (e: Exception) {
|
||
|
|
log.warn("job tick failed: {}", e.message ?: e.javaClass.simpleName)
|
||
|
|
}
|
||
|
|
if (running) runCatching { Thread.sleep(Duration.ofSeconds(30).toMillis()) }
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private fun maybeHistorySweep() {
|
||
|
|
val today = LocalDate.now(zone)
|
||
|
|
if (lastHistoryDay == today) return
|
||
|
|
val now = java.time.LocalTime.now(zone)
|
||
|
|
if ((now.hour == 3 && now.minute >= 30) || now.hour > 3) {
|
||
|
|
val outcome = historySweep.run()
|
||
|
|
lastHistoryDay = today
|
||
|
|
if (outcome.selected > 0 || outcome.snapLogPurged > 0) {
|
||
|
|
log.info("history sweep: {}", outcome)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|