feat(ingress): 实现 JDBC 信箱轮询、入站持久化与对拍测试 (U05)

This commit is contained in:
windyboy
2026-09-07 15:11:33 +08:00
parent dc68f1e1f8
commit c7b4b527ef
51 changed files with 1005 additions and 235 deletions
@@ -0,0 +1,55 @@
package com.gzzn.omms.msgexchange.infra.health
import com.gzzn.omms.msgexchange.delivery.DeliveryPort
import com.gzzn.omms.msgexchange.infra.redis.FlightRedisClient
import io.micronaut.context.BeanProvider
import io.micronaut.core.async.publisher.Publishers
import io.micronaut.health.HealthStatus
import io.micronaut.management.health.indicator.HealthIndicator
import io.micronaut.management.health.indicator.HealthResult
import jakarta.inject.Singleton
import org.reactivestreams.Publisher
/**
* U12(R05):阶段 A 关键依赖的自定义健康指示器——
* RedisflightInfo 权威存储)与 Kafka(投递端口)。经 BeanProvider 可选解析:
* 缺 bean(如未用 stub 也未实装)时指示 DOWN 而非启动失败;
* UP 判据为真实 pingfalse/异常 → DOWN),而非仅 bean 存在(复审 P1 修正)。
*/
@Singleton
class FlightRedisHealthIndicator(
private val redis: BeanProvider<FlightRedisClient>,
) : HealthIndicator {
override fun getResult(): Publisher<HealthResult> =
Publishers.just(redisHealth(if (redis.isPresent) redis.get() else null))
}
@Singleton
class KafkaDeliveryHealthIndicator(
private val port: BeanProvider<DeliveryPort>,
) : HealthIndicator {
override fun getResult(): Publisher<HealthResult> =
Publishers.just(kafkaHealth(if (port.isPresent) port.get() else null))
}
/** ping 判定独立成纯函数便于单测:client 为 null = bean 缺失;ping false/异常 = DOWN。 */
internal fun redisHealth(client: FlightRedisClient?): HealthResult =
healthOf("redis-flight-store", "flight store", client?.let {
try { it.ping() } catch (e: Exception) { false }
})
internal fun kafkaHealth(port: DeliveryPort?): HealthResult =
healthOf("kafka-delivery", "delivery port", port?.let {
try { it.ping() } catch (e: Exception) { false }
})
private fun healthOf(name: String, what: String, pingOk: Boolean?): HealthResult {
val (status, message) = when (pingOk) {
null -> HealthStatus.DOWN to "$what bean missing (stub off, impl pending)"
false -> HealthStatus.DOWN to "$what ping failed"
true -> HealthStatus.UP to "$what ping ok"
}
return HealthResult.builder(name).status(status).details(mapOf("message" to message)).build()
}