feat: enhance volume backup scheduling and management

- Added initVolumeBackupsCronJobs function to initialize scheduled volume backups on server startup.
- Updated volumeBackupsRouter to handle scheduling and removal of volume backup jobs based on user input.
- Improved create and update volume backup logic to include scheduling functionality for both cloud and local environments.
- Introduced utility functions for scheduling and removing volume backup jobs, enhancing overall backup management.
This commit is contained in:
Mauricio Siu
2025-07-02 00:36:46 -06:00
parent c5311f2a9f
commit 6521491e2f
6 changed files with 104 additions and 16 deletions

View File

@@ -6,6 +6,8 @@ import {
runVolumeBackup,
findVolumeBackupById,
restoreVolume,
scheduleVolumeBackup,
removeVolumeBackupJob,
} from "@dokploy/server";
import {
createVolumeBackupSchema,
@@ -21,6 +23,8 @@ import {
execAsyncRemote,
execAsyncStream,
} from "@dokploy/server/utils/process/execAsync";
import { removeJob, schedule, updateJob } from "@/server/utils/backup";
import { TRPCError } from "@trpc/server";
export const volumeBackupsRouter = createTRPCRouter({
list: protectedProcedure
@@ -55,7 +59,20 @@ export const volumeBackupsRouter = createTRPCRouter({
create: protectedProcedure
.input(createVolumeBackupSchema)
.mutation(async ({ input }) => {
return await createVolumeBackup(input);
const newVolumeBackup = await createVolumeBackup(input);
if (newVolumeBackup?.enabled) {
if (IS_CLOUD) {
await schedule({
cronSchedule: newVolumeBackup.cronExpression,
volumeBackupId: newVolumeBackup.volumeBackupId,
type: "volume-backup",
});
} else {
await scheduleVolumeBackup(newVolumeBackup.volumeBackupId);
}
}
return newVolumeBackup;
}),
one: protectedProcedure
.input(
@@ -73,15 +90,46 @@ export const volumeBackupsRouter = createTRPCRouter({
}),
)
.mutation(async ({ input }) => {
if (IS_CLOUD) {
return true;
}
return await removeVolumeBackup(input.volumeBackupId);
}),
update: protectedProcedure
.input(updateVolumeBackupSchema)
.mutation(async ({ input }) => {
return await updateVolumeBackup(input.volumeBackupId, input);
const updatedVolumeBackup = await updateVolumeBackup(
input.volumeBackupId,
input,
);
if (!updatedVolumeBackup) {
throw new TRPCError({
code: "NOT_FOUND",
message: "Volume backup not found",
});
}
if (IS_CLOUD) {
if (updatedVolumeBackup.enabled) {
await updateJob({
cronSchedule: updatedVolumeBackup.cronExpression,
volumeBackupId: updatedVolumeBackup.volumeBackupId,
type: "volume-backup",
});
} else {
await removeJob({
cronSchedule: updatedVolumeBackup.cronExpression,
volumeBackupId: updatedVolumeBackup.volumeBackupId,
type: "volume-backup",
});
}
} else {
if (updatedVolumeBackup?.enabled) {
removeVolumeBackupJob(updatedVolumeBackup.volumeBackupId);
scheduleVolumeBackup(updatedVolumeBackup.volumeBackupId);
} else {
removeVolumeBackupJob(updatedVolumeBackup.volumeBackupId);
}
}
return updatedVolumeBackup;
}),
runManually: protectedProcedure

View File

@@ -7,6 +7,7 @@ import {
createDefaultTraefikConfig,
initCronJobs,
initSchedules,
initVolumeBackupsCronJobs,
initializeNetwork,
sendDokployRestartNotifications,
setupDirectories,
@@ -51,6 +52,7 @@ void app.prepare().then(async () => {
await migration();
await initCronJobs();
await initSchedules();
await initVolumeBackupsCronJobs();
await sendDokployRestartNotifications();
}

View File

@@ -19,6 +19,11 @@ type QueueJob =
type: "schedule";
cronSchedule: string;
scheduleId: string;
}
| {
type: "volume-backup";
cronSchedule: string;
volumeBackupId: string;
};
export const schedule = async (job: QueueJob) => {
try {