From 4e38925119cc22d84cc8b0822aff58ea2b9b48a5 Mon Sep 17 00:00:00 2001 From: Mauricio Siu Date: Tue, 1 Sep 2026 01:31:59 -0600 Subject: [PATCH] fix: pass timezone when removing repeatable schedule job MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit removeJob() for type 'schedule' computed the BullMQ repeatable key using only the cron pattern, without the timezone. scheduleJob() always registers the repeatable job with tz set (job.timezone || UTC), so BullMQ's repeat key (name:jobId:endDate:tz:pattern) never matched on removal — removeRepeatable silently no-op'd and the job kept firing forever, surviving disable, delete, and reboots. Forward timezone through removeJob (queue.ts), the /update-backup lookup (index.ts), and the disable/delete call sites in the schedule router. --- apps/dokploy/server/api/routers/schedule.ts | 2 ++ apps/schedules/src/index.ts | 1 + apps/schedules/src/queue.ts | 3 ++- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/dokploy/server/api/routers/schedule.ts b/apps/dokploy/server/api/routers/schedule.ts index 8629d7546..a7417a92c 100644 --- a/apps/dokploy/server/api/routers/schedule.ts +++ b/apps/dokploy/server/api/routers/schedule.ts @@ -141,6 +141,7 @@ export const scheduleRouter = createTRPCRouter({ cronSchedule: updatedSchedule.cronExpression, scheduleId: updatedSchedule.scheduleId, type: "schedule", + timezone: updatedSchedule.timezone, }); } } else { @@ -185,6 +186,7 @@ export const scheduleRouter = createTRPCRouter({ cronSchedule: scheduleItem.cronExpression, scheduleId: scheduleItem.scheduleId, type: "schedule", + timezone: scheduleItem.timezone, }); } else { removeScheduleJob(scheduleItem.scheduleId); diff --git a/apps/schedules/src/index.ts b/apps/schedules/src/index.ts index a5f0fd47c..28eacbe1c 100644 --- a/apps/schedules/src/index.ts +++ b/apps/schedules/src/index.ts @@ -60,6 +60,7 @@ app.post("/update-backup", zValidator("json", jobQueueSchema), async (c) => { scheduleId: data.scheduleId, type: "schedule", cronSchedule: job.pattern || "", + timezone: job.tz || data.timezone, }); } else if (data.type === "volume-backup") { result = await removeJob({ diff --git a/apps/schedules/src/queue.ts b/apps/schedules/src/queue.ts index 7b0c48315..3d9b2c802 100644 --- a/apps/schedules/src/queue.ts +++ b/apps/schedules/src/queue.ts @@ -66,9 +66,10 @@ export const removeJob = async (data: QueueJob) => { return result; } if (data.type === "schedule") { - const { scheduleId, cronSchedule } = data; + const { scheduleId, cronSchedule, timezone } = data; const result = await jobQueue.removeRepeatable(scheduleId, { pattern: cronSchedule, + tz: timezone || "UTC", }); return result; }