🌳
pt0/deployF/dbF/validateWalRecencyAI.mts
6const defaultMaxStalenessMs = 2 * 60 * 60 * 1000
8export const validateWalRecency = async ({bucket_name, serverName, maxStalenessMs = defaultMaxStalenessMs}: {
9 bucket_name: string, serverName: string, maxStalenessMs?: number
10}) => {
11 const placement = bktPlacementH[bucket_name]
12 // a multi-cluster (or external) bucket is inherently redundant, so a DB sharing one of its
13 // clusters is NOT a single point of failure.
14 const bktClusters: string[] = placement?.external ? ['<external>'] : (placement?.clusters ?? [])
15 const dbClusterName = dbBackupCtx.getStore()?.dbClusterName
16 const isCrossCluster = !dbClusterName ? false : bktClusters.length > 1 ? true : bktClusters[0] !== dbClusterName
18 if (placement?.external) {
19 console.log(chalkGreen(`BACKUP EXTERNAL: ${serverName} backs up to third-party ${bucket_name}`))
20 } else if (dbClusterName && bktClusters.length === 1 && bktClusters[0] === dbClusterName) {
21 console.log(chalkRed(`BACKUP SAME CLUSTER: ${serverName} (db: ${dbClusterName}) backs up to single-cluster ${bucket_name} (bkt: ${bktClusters[0]})`))
22 } else if (dbClusterName && !bktClusters.length) {
23 console.log(chalkYellow(`BACKUP CLUSTER UNKNOWN: ${bucket_name} missing from bktPlacementH (pt0/bktF/bktPlacementF.mts)`))
24 }
26 const prefix = `${serverName}/${serverName}/wals/`
27 const contentsA = await listObjectsByPrefix({bucket_name, prefix})
28 let latestWalTime: Date | undefined
29 for (const obj of contentsA) {
30 if (!latestWalTime || (obj.LastModified && obj.LastModified > latestWalTime)) {
31 latestWalTime = obj.LastModified
32 }
33 }
35 const now = new Date()
36 const stalenessMs = latestWalTime ? now.getTime() - latestWalTime.getTime() : Infinity
37 const isFresh = stalenessMs <= maxStalenessMs
39 if (!latestWalTime) {
40 console.log(chalkRed(`WAL STALE: no WAL files found in s3://${bucket_name}/${prefix}`))
41 } else if (!isFresh) {
42 const hrs = Math.round(stalenessMs / 3600000 * 10) / 10
43 console.log(chalkRed(`WAL STALE: last WAL for ${serverName} is ${hrs}h old (threshold: ${maxStalenessMs / 3600000}h)`))
44 } else {
45 console.log(chalkGreen(`WAL OK: last WAL for ${serverName} is ${Math.round(stalenessMs / 60000)}m old`))
46 }
48 return {isFresh, isCrossCluster, lastWalTime: latestWalTime, stalenessMs}