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

View File

@@ -8,7 +8,7 @@ import { findEnvironmentById } from "@dokploy/server/services/environment";
import { findProjectById } from "@dokploy/server/services/project";
import { sendDatabaseBackupNotifications } from "../notifications/database-backup";
import { execAsync, execAsyncRemote } from "../process/execAsync";
import { getBackupCommand, getS3Credentials, normalizeS3Path } from "./utils";
import { getBackupCommand, getBackupTimestamp, getS3Credentials, normalizeS3Path } from "./utils";
export const runComposeBackup = async (
compose: Compose,
@@ -19,12 +19,7 @@ export const runComposeBackup = async (
const project = await findProjectById(environment.projectId);
const { prefix, databaseType, serviceName } = backup;
const destination = backup.destination;
const timestamp = new Date()
.toISOString()
.replace("T", "_")
.replace(/:/g, "-")
.replace(".", "_");
const backupFileName = `${timestamp}.${databaseType === "mongo" ? "bson" : "sql"}.gz`;
const backupFileName = `${getBackupTimestamp()}.${databaseType === "mongo" ? "bson" : "sql"}.gz`;
const s3AppName = serviceName ? `${appName}_${serviceName}` : appName;
const bucketDestination = `${s3AppName}/${normalizeS3Path(prefix)}${backupFileName}`;
const deployment = await createDeploymentBackup({

View File

@@ -8,7 +8,7 @@ import type { Libsql } from "@dokploy/server/services/libsql";
import { findProjectById } from "@dokploy/server/services/project";
import { sendDatabaseBackupNotifications } from "../notifications/database-backup";
import { execAsync, execAsyncRemote } from "../process/execAsync";
import { getBackupCommand, getS3Credentials, normalizeS3Path } from "./utils";
import { getBackupCommand, getBackupTimestamp, getS3Credentials, normalizeS3Path } from "./utils";
export const runLibsqlBackup = async (
libsql: Libsql,
@@ -25,7 +25,7 @@ export const runLibsqlBackup = async (
});
const { prefix } = backup;
const destination = backup.destination;
const backupFileName = `${new Date().toISOString()}.sql.gz`;
const backupFileName = `${getBackupTimestamp()}.sql.gz`;
const bucketDestination = `${appName}/${normalizeS3Path(prefix)}${backupFileName}`;
try {
const rcloneFlags = getS3Credentials(destination);

View File

@@ -8,7 +8,7 @@ import type { Mariadb } from "@dokploy/server/services/mariadb";
import { findProjectById } from "@dokploy/server/services/project";
import { sendDatabaseBackupNotifications } from "../notifications/database-backup";
import { execAsync, execAsyncRemote } from "../process/execAsync";
import { getBackupCommand, getS3Credentials, normalizeS3Path } from "./utils";
import { getBackupCommand, getBackupTimestamp, getS3Credentials, normalizeS3Path } from "./utils";
export const runMariadbBackup = async (
mariadb: Mariadb,
@@ -19,12 +19,7 @@ export const runMariadbBackup = async (
const project = await findProjectById(environment.projectId);
const { prefix } = backup;
const destination = backup.destination;
const timestamp = new Date()
.toISOString()
.replace("T", "_")
.replace(/:/g, "-")
.replace(".", "_");
const backupFileName = `${timestamp}.sql.gz`;
const backupFileName = `${getBackupTimestamp()}.sql.gz`;
const bucketDestination = `${appName}/${normalizeS3Path(prefix)}${backupFileName}`;
const deployment = await createDeploymentBackup({
backupId: backup.backupId,

View File

@@ -8,7 +8,7 @@ import type { Mongo } from "@dokploy/server/services/mongo";
import { findProjectById } from "@dokploy/server/services/project";
import { sendDatabaseBackupNotifications } from "../notifications/database-backup";
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) => {
const { environmentId, name, appName } = mongo;
@@ -16,12 +16,7 @@ export const runMongoBackup = async (mongo: Mongo, backup: BackupSchedule) => {
const project = await findProjectById(environment.projectId);
const { prefix } = backup;
const destination = backup.destination;
const timestamp = new Date()
.toISOString()
.replace("T", "_")
.replace(/:/g, "-")
.replace(".", "_");
const backupFileName = `${timestamp}.bson.gz`;
const backupFileName = `${getBackupTimestamp()}.bson.gz`;
const bucketDestination = `${appName}/${normalizeS3Path(prefix)}${backupFileName}`;
const deployment = await createDeploymentBackup({
backupId: backup.backupId,

View File

@@ -8,7 +8,7 @@ import type { MySql } from "@dokploy/server/services/mysql";
import { findProjectById } from "@dokploy/server/services/project";
import { sendDatabaseBackupNotifications } from "../notifications/database-backup";
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) => {
const { environmentId, name, appName } = mysql;
@@ -16,12 +16,7 @@ export const runMySqlBackup = async (mysql: MySql, backup: BackupSchedule) => {
const project = await findProjectById(environment.projectId);
const { prefix } = backup;
const destination = backup.destination;
const timestamp = new Date()
.toISOString()
.replace("T", "_")
.replace(/:/g, "-")
.replace(".", "_");
const backupFileName = `${timestamp}.sql.gz`;
const backupFileName = `${getBackupTimestamp()}.sql.gz`;
const bucketDestination = `${appName}/${normalizeS3Path(prefix)}${backupFileName}`;
const deployment = await createDeploymentBackup({
backupId: backup.backupId,

View File

@@ -8,7 +8,7 @@ import type { Postgres } from "@dokploy/server/services/postgres";
import { findProjectById } from "@dokploy/server/services/project";
import { sendDatabaseBackupNotifications } from "../notifications/database-backup";
import { execAsync, execAsyncRemote } from "../process/execAsync";
import { getBackupCommand, getS3Credentials, normalizeS3Path } from "./utils";
import { getBackupCommand, getBackupTimestamp, getS3Credentials, normalizeS3Path } from "./utils";
export const runPostgresBackup = async (
postgres: Postgres,
@@ -25,12 +25,7 @@ export const runPostgresBackup = async (
});
const { prefix } = backup;
const destination = backup.destination;
const timestamp = new Date()
.toISOString()
.replace("T", "_")
.replace(/:/g, "-")
.replace(".", "_");
const backupFileName = `${timestamp}.sql.gz`;
const backupFileName = `${getBackupTimestamp()}.sql.gz`;
const bucketDestination = `${appName}/${normalizeS3Path(prefix)}${backupFileName}`;
try {
const rcloneFlags = getS3Credentials(destination);

View File

@@ -56,6 +56,9 @@ export const removeScheduleBackup = (backupId: string) => {
currentJob?.cancel();
};
export const getBackupTimestamp = () =>
new Date().toISOString().replace(/[:.]/g, "-");
export const normalizeS3Path = (prefix: string) => {
// Trim whitespace and remove leading/trailing slashes
const normalizedPrefix = prefix.trim().replace(/^\/+|\/+$/g, "");

View File

@@ -11,7 +11,7 @@ import {
import { findDestinationById } from "@dokploy/server/services/destination";
import { sendDokployBackupNotifications } from "../notifications/dokploy-backup";
import { execAsync } from "../process/execAsync";
import { getS3Credentials, normalizeS3Path } from "./utils";
import { getBackupTimestamp, getS3Credentials, normalizeS3Path } from "./utils";
function formatBytes(bytes?: number) {
if (bytes === undefined) return "Unknown size";
@@ -37,7 +37,7 @@ export const runWebServerBackup = async (backup: BackupSchedule) => {
try {
const destination = await findDestinationById(backup.destinationId);
const rcloneFlags = getS3Credentials(destination);
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
const timestamp = getBackupTimestamp();
const { BASE_PATH } = paths();
const tempDir = await mkdtemp(join(tmpdir(), "dokploy-backup-"));
const backupFileName = `webserver-backup-${timestamp}.zip`;

View File

@@ -2,7 +2,7 @@ import path from "node:path";
import { paths } from "@dokploy/server/constants";
import { findComposeById } from "@dokploy/server/services/compose";
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 = (
volumeBackup: Awaited<ReturnType<typeof findVolumeBackupById>>,
@@ -32,12 +32,7 @@ export const backupVolume = async (
const { VOLUME_BACKUPS_PATH, VOLUME_BACKUP_LOCK_PATH } = paths(!!serverId);
const destination = volumeBackup.destination;
const s3AppName = getVolumeServiceAppName(volumeBackup);
const timestamp = new Date()
.toISOString()
.replace("T", "_")
.replace(/:/g, "-")
.replace(".", "_");
const backupFileName = `${volumeName}-${timestamp}.tar`;
const backupFileName = `${volumeName}-${getBackupTimestamp()}.tar`;
const bucketDestination = `${s3AppName}/${normalizeS3Path(prefix || "")}${backupFileName}`;
const rcloneFlags = getS3Credentials(volumeBackup.destination);
const rcloneDestination = `:s3:${destination.bucket}/${bucketDestination}`;