Files
pikasTech-unidesk/scripts/src/platform-db-postgres-backups.ts
T
2026-07-15 06:20:43 +02:00

91 lines
3.1 KiB
TypeScript

export interface LogicalDumpConfig {
enabled: boolean;
database: string;
scriptPath: string;
serviceName: string;
timerName: string;
schedule: string;
retentionDays: number;
warningAfterHours: number;
destination: { type: string; path: string };
pgDump: { host: string; format: "custom" };
encryption: { enabled: boolean };
}
export interface LogicalDumpRuntimeFact {
database: string;
databaseExists: boolean;
scriptPath: string;
scriptExists: boolean;
serviceName: string;
serviceResult: string | null;
serviceExitStatus: number | null;
lastSuccessAt: string | null;
timerName: string;
timerActive: boolean;
timerEnabled: boolean;
nextRunAt: string | null;
latestNonEmptyDump: {
path: string;
bytes: number;
modifiedAt: string;
} | null;
}
export interface LogicalDumpProjection extends LogicalDumpConfig {
observed: LogicalDumpRuntimeFact | null;
recoverability: {
recoverable: boolean;
latestNonEmptyDump: LogicalDumpRuntimeFact["latestNonEmptyDump"];
};
warnings: string[];
}
export function projectLogicalDumps(
declarations: LogicalDumpConfig[],
facts: LogicalDumpRuntimeFact[] | null,
observedAt = Date.now(),
): LogicalDumpProjection[] {
return declarations.map((declaration) => {
const observed = facts?.find((item) => item.database === declaration.database && item.timerName === declaration.timerName) ?? null;
const warnings: string[] = [];
if (!declaration.enabled) return projection(declaration, observed, warnings);
if (observed === null) {
warnings.push("backup-observation-unavailable");
return projection(declaration, observed, warnings);
}
if (!observed.databaseExists) warnings.push("backup-database-missing");
if (!observed.scriptExists) warnings.push("backup-script-missing");
if (!observed.timerEnabled) warnings.push("backup-timer-disabled");
if (!observed.timerActive) warnings.push("backup-timer-inactive");
if (observed.lastSuccessAt === null) warnings.push("backup-recent-success-missing");
if (observed.latestNonEmptyDump === null) {
warnings.push("backup-latest-non-empty-dump-missing");
} else {
const modifiedAt = Date.parse(observed.latestNonEmptyDump.modifiedAt);
if (!Number.isFinite(modifiedAt) || observedAt - modifiedAt > declaration.warningAfterHours * 60 * 60 * 1000) {
warnings.push("backup-latest-dump-stale");
}
}
if (observed.serviceResult !== null && observed.serviceResult !== "success") warnings.push("backup-last-run-failed");
if (observed.serviceExitStatus !== null && observed.serviceExitStatus !== 0) warnings.push("backup-last-run-nonzero");
return projection(declaration, observed, warnings);
});
}
function projection(
declaration: LogicalDumpConfig,
observed: LogicalDumpRuntimeFact | null,
warnings: string[],
): LogicalDumpProjection {
return {
...declaration,
observed,
recoverability: {
recoverable: observed?.databaseExists === true && observed.latestNonEmptyDump !== null,
latestNonEmptyDump: observed?.latestNonEmptyDump ?? null,
},
warnings,
};
}