refactor(backups): standardize backup file naming using getBackupTimestamp utility

- Replaced inline timestamp generation with the new getBackupTimestamp function across various backup modules (compose, libsql, mariadb, mongo, mysql, postgres, web-server, and volume-backups).
- Improved code readability and maintainability by centralizing timestamp formatting logic.
This commit is contained in:
Mauricio Siu
2026-04-03 17:13:00 -06:00
parent 6192c08400
commit 71de71fb8a
9 changed files with 19 additions and 46 deletions
+2 -7
View File
@@ -8,7 +8,7 @@ import { findEnvironmentById } from "@dokploy/server/services/environment";
import { findProjectById } from "@dokploy/server/services/project"; import { findProjectById } from "@dokploy/server/services/project";
import { sendDatabaseBackupNotifications } from "../notifications/database-backup"; import { sendDatabaseBackupNotifications } from "../notifications/database-backup";
import { execAsync, execAsyncRemote } from "../process/execAsync"; import { execAsync, execAsyncRemote } from "../process/execAsync";
import { getBackupCommand, getS3Credentials, normalizeS3Path } from "./utils"; import { getBackupCommand, getBackupTimestamp, getS3Credentials, normalizeS3Path } from "./utils";
export const runComposeBackup = async ( export const runComposeBackup = async (
compose: Compose, compose: Compose,
@@ -19,12 +19,7 @@ export const runComposeBackup = async (
const project = await findProjectById(environment.projectId); const project = await findProjectById(environment.projectId);
const { prefix, databaseType, serviceName } = backup; const { prefix, databaseType, serviceName } = backup;
const destination = backup.destination; const destination = backup.destination;
const timestamp = new Date() const backupFileName = `${getBackupTimestamp()}.${databaseType === "mongo" ? "bson" : "sql"}.gz`;
.toISOString()
.replace("T", "_")
.replace(/:/g, "-")
.replace(".", "_");
const backupFileName = `${timestamp}.${databaseType === "mongo" ? "bson" : "sql"}.gz`;
const s3AppName = serviceName ? `${appName}_${serviceName}` : appName; const s3AppName = serviceName ? `${appName}_${serviceName}` : appName;
const bucketDestination = `${s3AppName}/${normalizeS3Path(prefix)}${backupFileName}`; const bucketDestination = `${s3AppName}/${normalizeS3Path(prefix)}${backupFileName}`;
const deployment = await createDeploymentBackup({ const deployment = await createDeploymentBackup({
+2 -2
View File
@@ -8,7 +8,7 @@ import type { Libsql } from "@dokploy/server/services/libsql";
import { findProjectById } from "@dokploy/server/services/project"; import { findProjectById } from "@dokploy/server/services/project";
import { sendDatabaseBackupNotifications } from "../notifications/database-backup"; import { sendDatabaseBackupNotifications } from "../notifications/database-backup";
import { execAsync, execAsyncRemote } from "../process/execAsync"; import { execAsync, execAsyncRemote } from "../process/execAsync";
import { getBackupCommand, getS3Credentials, normalizeS3Path } from "./utils"; import { getBackupCommand, getBackupTimestamp, getS3Credentials, normalizeS3Path } from "./utils";
export const runLibsqlBackup = async ( export const runLibsqlBackup = async (
libsql: Libsql, libsql: Libsql,
@@ -25,7 +25,7 @@ export const runLibsqlBackup = async (
}); });
const { prefix } = backup; const { prefix } = backup;
const destination = backup.destination; const destination = backup.destination;
const backupFileName = `${new Date().toISOString()}.sql.gz`; const backupFileName = `${getBackupTimestamp()}.sql.gz`;
const bucketDestination = `${appName}/${normalizeS3Path(prefix)}${backupFileName}`; const bucketDestination = `${appName}/${normalizeS3Path(prefix)}${backupFileName}`;
try { try {
const rcloneFlags = getS3Credentials(destination); const rcloneFlags = getS3Credentials(destination);
+2 -7
View File
@@ -8,7 +8,7 @@ import type { Mariadb } from "@dokploy/server/services/mariadb";
import { findProjectById } from "@dokploy/server/services/project"; import { findProjectById } from "@dokploy/server/services/project";
import { sendDatabaseBackupNotifications } from "../notifications/database-backup"; import { sendDatabaseBackupNotifications } from "../notifications/database-backup";
import { execAsync, execAsyncRemote } from "../process/execAsync"; import { execAsync, execAsyncRemote } from "../process/execAsync";
import { getBackupCommand, getS3Credentials, normalizeS3Path } from "./utils"; import { getBackupCommand, getBackupTimestamp, getS3Credentials, normalizeS3Path } from "./utils";
export const runMariadbBackup = async ( export const runMariadbBackup = async (
mariadb: Mariadb, mariadb: Mariadb,
@@ -19,12 +19,7 @@ export const runMariadbBackup = async (
const project = await findProjectById(environment.projectId); const project = await findProjectById(environment.projectId);
const { prefix } = backup; const { prefix } = backup;
const destination = backup.destination; const destination = backup.destination;
const timestamp = new Date() const backupFileName = `${getBackupTimestamp()}.sql.gz`;
.toISOString()
.replace("T", "_")
.replace(/:/g, "-")
.replace(".", "_");
const backupFileName = `${timestamp}.sql.gz`;
const bucketDestination = `${appName}/${normalizeS3Path(prefix)}${backupFileName}`; const bucketDestination = `${appName}/${normalizeS3Path(prefix)}${backupFileName}`;
const deployment = await createDeploymentBackup({ const deployment = await createDeploymentBackup({
backupId: backup.backupId, backupId: backup.backupId,
+2 -7
View File
@@ -8,7 +8,7 @@ import type { Mongo } from "@dokploy/server/services/mongo";
import { findProjectById } from "@dokploy/server/services/project"; import { findProjectById } from "@dokploy/server/services/project";
import { sendDatabaseBackupNotifications } from "../notifications/database-backup"; import { sendDatabaseBackupNotifications } from "../notifications/database-backup";
import { execAsync, execAsyncRemote } from "../process/execAsync"; import { execAsync, execAsyncRemote } from "../process/execAsync";
import { getBackupCommand, getS3Credentials, normalizeS3Path } from "./utils"; import { getBackupCommand, getBackupTimestamp, getS3Credentials, normalizeS3Path } from "./utils";
export const runMongoBackup = async (mongo: Mongo, backup: BackupSchedule) => { export const runMongoBackup = async (mongo: Mongo, backup: BackupSchedule) => {
const { environmentId, name, appName } = mongo; const { environmentId, name, appName } = mongo;
@@ -16,12 +16,7 @@ export const runMongoBackup = async (mongo: Mongo, backup: BackupSchedule) => {
const project = await findProjectById(environment.projectId); const project = await findProjectById(environment.projectId);
const { prefix } = backup; const { prefix } = backup;
const destination = backup.destination; const destination = backup.destination;
const timestamp = new Date() const backupFileName = `${getBackupTimestamp()}.bson.gz`;
.toISOString()
.replace("T", "_")
.replace(/:/g, "-")
.replace(".", "_");
const backupFileName = `${timestamp}.bson.gz`;
const bucketDestination = `${appName}/${normalizeS3Path(prefix)}${backupFileName}`; const bucketDestination = `${appName}/${normalizeS3Path(prefix)}${backupFileName}`;
const deployment = await createDeploymentBackup({ const deployment = await createDeploymentBackup({
backupId: backup.backupId, backupId: backup.backupId,
+2 -7
View File
@@ -8,7 +8,7 @@ import type { MySql } from "@dokploy/server/services/mysql";
import { findProjectById } from "@dokploy/server/services/project"; import { findProjectById } from "@dokploy/server/services/project";
import { sendDatabaseBackupNotifications } from "../notifications/database-backup"; import { sendDatabaseBackupNotifications } from "../notifications/database-backup";
import { execAsync, execAsyncRemote } from "../process/execAsync"; import { execAsync, execAsyncRemote } from "../process/execAsync";
import { getBackupCommand, getS3Credentials, normalizeS3Path } from "./utils"; import { getBackupCommand, getBackupTimestamp, getS3Credentials, normalizeS3Path } from "./utils";
export const runMySqlBackup = async (mysql: MySql, backup: BackupSchedule) => { export const runMySqlBackup = async (mysql: MySql, backup: BackupSchedule) => {
const { environmentId, name, appName } = mysql; const { environmentId, name, appName } = mysql;
@@ -16,12 +16,7 @@ export const runMySqlBackup = async (mysql: MySql, backup: BackupSchedule) => {
const project = await findProjectById(environment.projectId); const project = await findProjectById(environment.projectId);
const { prefix } = backup; const { prefix } = backup;
const destination = backup.destination; const destination = backup.destination;
const timestamp = new Date() const backupFileName = `${getBackupTimestamp()}.sql.gz`;
.toISOString()
.replace("T", "_")
.replace(/:/g, "-")
.replace(".", "_");
const backupFileName = `${timestamp}.sql.gz`;
const bucketDestination = `${appName}/${normalizeS3Path(prefix)}${backupFileName}`; const bucketDestination = `${appName}/${normalizeS3Path(prefix)}${backupFileName}`;
const deployment = await createDeploymentBackup({ const deployment = await createDeploymentBackup({
backupId: backup.backupId, backupId: backup.backupId,
@@ -8,7 +8,7 @@ import type { Postgres } from "@dokploy/server/services/postgres";
import { findProjectById } from "@dokploy/server/services/project"; import { findProjectById } from "@dokploy/server/services/project";
import { sendDatabaseBackupNotifications } from "../notifications/database-backup"; import { sendDatabaseBackupNotifications } from "../notifications/database-backup";
import { execAsync, execAsyncRemote } from "../process/execAsync"; import { execAsync, execAsyncRemote } from "../process/execAsync";
import { getBackupCommand, getS3Credentials, normalizeS3Path } from "./utils"; import { getBackupCommand, getBackupTimestamp, getS3Credentials, normalizeS3Path } from "./utils";
export const runPostgresBackup = async ( export const runPostgresBackup = async (
postgres: Postgres, postgres: Postgres,
@@ -25,12 +25,7 @@ export const runPostgresBackup = async (
}); });
const { prefix } = backup; const { prefix } = backup;
const destination = backup.destination; const destination = backup.destination;
const timestamp = new Date() const backupFileName = `${getBackupTimestamp()}.sql.gz`;
.toISOString()
.replace("T", "_")
.replace(/:/g, "-")
.replace(".", "_");
const backupFileName = `${timestamp}.sql.gz`;
const bucketDestination = `${appName}/${normalizeS3Path(prefix)}${backupFileName}`; const bucketDestination = `${appName}/${normalizeS3Path(prefix)}${backupFileName}`;
try { try {
const rcloneFlags = getS3Credentials(destination); const rcloneFlags = getS3Credentials(destination);
@@ -56,6 +56,9 @@ export const removeScheduleBackup = (backupId: string) => {
currentJob?.cancel(); currentJob?.cancel();
}; };
export const getBackupTimestamp = () =>
new Date().toISOString().replace(/[:.]/g, "-");
export const normalizeS3Path = (prefix: string) => { export const normalizeS3Path = (prefix: string) => {
// Trim whitespace and remove leading/trailing slashes // Trim whitespace and remove leading/trailing slashes
const normalizedPrefix = prefix.trim().replace(/^\/+|\/+$/g, ""); const normalizedPrefix = prefix.trim().replace(/^\/+|\/+$/g, "");
@@ -11,7 +11,7 @@ import {
import { findDestinationById } from "@dokploy/server/services/destination"; import { findDestinationById } from "@dokploy/server/services/destination";
import { sendDokployBackupNotifications } from "../notifications/dokploy-backup"; import { sendDokployBackupNotifications } from "../notifications/dokploy-backup";
import { execAsync } from "../process/execAsync"; import { execAsync } from "../process/execAsync";
import { getS3Credentials, normalizeS3Path } from "./utils"; import { getBackupTimestamp, getS3Credentials, normalizeS3Path } from "./utils";
function formatBytes(bytes?: number) { function formatBytes(bytes?: number) {
if (bytes === undefined) return "Unknown size"; if (bytes === undefined) return "Unknown size";
@@ -37,7 +37,7 @@ export const runWebServerBackup = async (backup: BackupSchedule) => {
try { try {
const destination = await findDestinationById(backup.destinationId); const destination = await findDestinationById(backup.destinationId);
const rcloneFlags = getS3Credentials(destination); const rcloneFlags = getS3Credentials(destination);
const timestamp = new Date().toISOString().replace(/[:.]/g, "-"); const timestamp = getBackupTimestamp();
const { BASE_PATH } = paths(); const { BASE_PATH } = paths();
const tempDir = await mkdtemp(join(tmpdir(), "dokploy-backup-")); const tempDir = await mkdtemp(join(tmpdir(), "dokploy-backup-"));
const backupFileName = `webserver-backup-${timestamp}.zip`; const backupFileName = `webserver-backup-${timestamp}.zip`;
@@ -2,7 +2,7 @@ import path from "node:path";
import { paths } from "@dokploy/server/constants"; import { paths } from "@dokploy/server/constants";
import { findComposeById } from "@dokploy/server/services/compose"; import { findComposeById } from "@dokploy/server/services/compose";
import type { findVolumeBackupById } from "@dokploy/server/services/volume-backups"; import type { findVolumeBackupById } from "@dokploy/server/services/volume-backups";
import { getS3Credentials, normalizeS3Path } from "../backups/utils"; import { getBackupTimestamp, getS3Credentials, normalizeS3Path } from "../backups/utils";
export const getVolumeServiceAppName = ( export const getVolumeServiceAppName = (
volumeBackup: Awaited<ReturnType<typeof findVolumeBackupById>>, volumeBackup: Awaited<ReturnType<typeof findVolumeBackupById>>,
@@ -32,12 +32,7 @@ export const backupVolume = async (
const { VOLUME_BACKUPS_PATH, VOLUME_BACKUP_LOCK_PATH } = paths(!!serverId); const { VOLUME_BACKUPS_PATH, VOLUME_BACKUP_LOCK_PATH } = paths(!!serverId);
const destination = volumeBackup.destination; const destination = volumeBackup.destination;
const s3AppName = getVolumeServiceAppName(volumeBackup); const s3AppName = getVolumeServiceAppName(volumeBackup);
const timestamp = new Date() const backupFileName = `${volumeName}-${getBackupTimestamp()}.tar`;
.toISOString()
.replace("T", "_")
.replace(/:/g, "-")
.replace(".", "_");
const backupFileName = `${volumeName}-${timestamp}.tar`;
const bucketDestination = `${s3AppName}/${normalizeS3Path(prefix || "")}${backupFileName}`; const bucketDestination = `${s3AppName}/${normalizeS3Path(prefix || "")}${backupFileName}`;
const rcloneFlags = getS3Credentials(volumeBackup.destination); const rcloneFlags = getS3Credentials(volumeBackup.destination);
const rcloneDestination = `:s3:${destination.bucket}/${bucketDestination}`; const rcloneDestination = `:s3:${destination.bucket}/${bucketDestination}`;