6const defaultMaxStalenessMs = 2 * 60 * 60 * 1000 8export const validateWalRecency = async ({bucket_name, serverName, maxStalenessMs = defaultMaxStalenessMs}: { 9 bucket_name: string, serverName: string, maxStalenessMs?: number 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)`)) 26 const prefix = `${serverName}/${serverName}/wals/` 28 let latestWalTime: Date | undefined 29 for (const obj of contentsA) { 30 if (!latestWalTime || (obj.LastModified && obj.LastModified > latestWalTime)) { 31 latestWalTime = obj.LastModified 35 const now = new Date() 36 const stalenessMs = latestWalTime ? now.getTime() - latestWalTime.getTime() : Infinity 37 const isFresh = stalenessMs <= maxStalenessMs 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)`)) 45 console.log(chalkGreen(`WAL OK: last WAL for ${serverName} is ${Math.round(stalenessMs / 60000)}m old`)) 48 return {isFresh, isCrossCluster, lastWalTime: latestWalTime, stalenessMs}