feat(volume-backup): add volume backup email notification template and integrate with notification system

This commit is contained in:
Mauricio Siu
2025-12-07 02:15:10 -06:00
parent bd751658be
commit f5de5130f3
6 changed files with 7074 additions and 119 deletions

View File

@@ -14,6 +14,51 @@ import { getS3Credentials, normalizeS3Path } from "../backups/utils";
import { sendVolumeBackupNotifications } from "../notifications/volume-backup";
import { backupVolume } from "./backup";
// Helper functions to extract project info from volume backup
const getProjectName = (
volumeBackup: Awaited<ReturnType<typeof findVolumeBackupById>>,
): string => {
const services = [
volumeBackup.application,
volumeBackup.compose,
volumeBackup.postgres,
volumeBackup.mysql,
volumeBackup.mariadb,
volumeBackup.mongo,
volumeBackup.redis,
];
for (const service of services) {
if (service?.environment?.project?.name) {
return service.environment.project.name;
}
}
return "Unknown Project";
};
const getOrganizationId = (
volumeBackup: Awaited<ReturnType<typeof findVolumeBackupById>>,
): string => {
const services = [
volumeBackup.application,
volumeBackup.compose,
volumeBackup.postgres,
volumeBackup.mysql,
volumeBackup.mariadb,
volumeBackup.mongo,
volumeBackup.redis,
];
for (const service of services) {
if (service?.environment?.project?.organizationId) {
return service.environment.project.organizationId;
}
}
return "";
};
export const scheduleVolumeBackup = async (volumeBackupId: string) => {
const volumeBackup = await findVolumeBackupById(volumeBackupId);
scheduleJob(volumeBackupId, volumeBackup.cronExpression, async () => {
@@ -62,7 +107,8 @@ export const runVolumeBackup = async (volumeBackupId: string) => {
title: "Volume Backup",
description: "Volume Backup",
});
const projectName = getProjectName(volumeBackup);
const organizationId = getOrganizationId(volumeBackup);
try {
const command = await backupVolume(volumeBackup);
@@ -79,55 +125,20 @@ export const runVolumeBackup = async (volumeBackupId: string) => {
await updateDeploymentStatus(deployment.deploymentId, "done");
// Send success notification
try {
const projectName =
volumeBackup.application?.environment?.project?.name ||
volumeBackup.compose?.environment?.project?.name ||
volumeBackup.postgres?.environment?.project?.name ||
volumeBackup.mysql?.environment?.project?.name ||
volumeBackup.mariadb?.environment?.project?.name ||
volumeBackup.mongo?.environment?.project?.name ||
volumeBackup.redis?.environment?.project?.name ||
"Unknown Project";
// Map service type to match notification function expectations
const mappedServiceType =
volumeBackup.serviceType === "mongo"
? "mongodb"
: volumeBackup.serviceType;
const organizationId =
volumeBackup.application?.environment?.project?.organizationId ||
volumeBackup.compose?.environment?.project?.organizationId ||
volumeBackup.postgres?.environment?.project?.organizationId ||
volumeBackup.mysql?.environment?.project?.organizationId ||
volumeBackup.mariadb?.environment?.project?.organizationId ||
volumeBackup.mongo?.environment?.project?.organizationId ||
volumeBackup.redis?.environment?.project?.organizationId ||
"";
// Map service type to match notification function expectations
const mappedServiceType =
volumeBackup.serviceType === "mongo"
? "mongodb"
: volumeBackup.serviceType;
await sendVolumeBackupNotifications({
projectName,
applicationName: volumeBackup.name,
volumeName: volumeBackup.volumeName,
serviceType: mappedServiceType as
| "application"
| "postgres"
| "mysql"
| "mongodb"
| "mariadb"
| "redis"
| "compose",
type: "success",
organizationId,
});
} catch (notificationError) {
console.error(
"Failed to send volume backup success notification:",
notificationError,
);
}
await sendVolumeBackupNotifications({
projectName,
applicationName: volumeBackup.name,
volumeName: volumeBackup.volumeName,
serviceType: mappedServiceType,
type: "success",
organizationId,
});
} catch (error) {
const { VOLUME_BACKUPS_PATH } = paths(!!serverId);
const volumeBackupPath = path.join(
@@ -144,56 +155,19 @@ export const runVolumeBackup = async (volumeBackupId: string) => {
await updateDeploymentStatus(deployment.deploymentId, "error");
// Send error notification
try {
const projectName =
volumeBackup.application?.environment?.project?.name ||
volumeBackup.compose?.environment?.project?.name ||
volumeBackup.postgres?.environment?.project?.name ||
volumeBackup.mysql?.environment?.project?.name ||
volumeBackup.mariadb?.environment?.project?.name ||
volumeBackup.mongo?.environment?.project?.name ||
volumeBackup.redis?.environment?.project?.name ||
"Unknown Project";
const mappedServiceType =
volumeBackup.serviceType === "mongo"
? "mongodb"
: volumeBackup.serviceType;
const organizationId =
volumeBackup.application?.environment?.project?.organizationId ||
volumeBackup.compose?.environment?.project?.organizationId ||
volumeBackup.postgres?.environment?.project?.organizationId ||
volumeBackup.mysql?.environment?.project?.organizationId ||
volumeBackup.mariadb?.environment?.project?.organizationId ||
volumeBackup.mongo?.environment?.project?.organizationId ||
volumeBackup.redis?.environment?.project?.organizationId ||
"";
// Map service type to match notification function expectations
const mappedServiceType =
volumeBackup.serviceType === "mongo"
? "mongodb"
: volumeBackup.serviceType;
await sendVolumeBackupNotifications({
projectName,
applicationName: volumeBackup.name,
volumeName: volumeBackup.volumeName,
serviceType: mappedServiceType as
| "application"
| "postgres"
| "mysql"
| "mongodb"
| "mariadb"
| "redis"
| "compose",
type: "error",
organizationId,
errorMessage: error instanceof Error ? error.message : String(error),
});
} catch (notificationError) {
console.error(
"Failed to send volume backup error notification:",
notificationError,
);
}
console.error(error);
await sendVolumeBackupNotifications({
projectName,
applicationName: volumeBackup.name,
volumeName: volumeBackup.volumeName,
serviceType: mappedServiceType,
type: "error",
organizationId,
errorMessage: error instanceof Error ? error.message : String(error),
});
}
};