/** Raw, non-sensitive replica state collected by the bounded read endpoint probe. */ export interface DatabaseReadReplicationSample { inRecovery: boolean receivedLsn: string | null replayedLsn: string | null lastReplayAtMs: number | null receiverStreaming: boolean receiverLastMessageReceiptAtMs: number | null } export interface DatabaseReadReplicationAssessment { replayLagMs: number | null replicationReceiverHealthy: boolean } const isFiniteNumber = (value: number | null): value is number => value !== null && Number.isFinite(value) /** * A quiet, caught-up standby can have an old last replayed transaction. Compare * the receive/replay WAL positions first; only age the replay timestamp while * there is a real backlog. A caught-up but disconnected receiver is still not * usable, so it separately needs a recent streaming heartbeat. */ export const assessDatabaseReadReplication = ( sample: DatabaseReadReplicationSample, observedAtMs: number, receiverFreshnessMs: number, ): DatabaseReadReplicationAssessment => { if (!sample.inRecovery) { return { replayLagMs: null, replicationReceiverHealthy: true } } const caughtUp = sample.receivedLsn !== null && sample.replayedLsn !== null && sample.receivedLsn === sample.replayedLsn const replayLagMs = caughtUp ? 0 : isFiniteNumber(sample.lastReplayAtMs) && Number.isFinite(observedAtMs) ? Math.max(0, observedAtMs - sample.lastReplayAtMs) : null const receiverAgeMs = isFiniteNumber(sample.receiverLastMessageReceiptAtMs) && Number.isFinite(observedAtMs) ? observedAtMs - sample.receiverLastMessageReceiptAtMs : null const replicationReceiverHealthy = sample.receiverStreaming && receiverAgeMs !== null && receiverAgeMs >= 0 && receiverAgeMs <= receiverFreshnessMs return { replayLagMs, replicationReceiverHealthy } }