From f12ecc335007aca85b45044f4337c11563b2dae2 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Tue, 11 Aug 2026 21:33:49 -0600 Subject: [PATCH] fix: don't cancel schedule deployments running outside the panel process on restart (#5053) Fixes #4986. initCancelDeployments blindly marked every 'running' deployment as 'cancelled' on boot, including schedule runs whose actual work (docker exec into another container, or SSH to a remote host) is decoupled from the Dokploy process and keeps running after a restart. Now only deployments with no schedule, or schedules of type dokploy-server (a real child process), get cancelled. Also resolve any stale 'running' deployment for a schedule when a new run starts, so restarted panels don't leave ghost 'running' rows forever. --- packages/server/src/services/deployment.ts | 13 ++++++++ .../src/utils/startup/cancel-deployments.ts | 33 +++++++++++++++++-- 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/packages/server/src/services/deployment.ts b/packages/server/src/services/deployment.ts index 18577a861..fd61fc106 100644 --- a/packages/server/src/services/deployment.ts +++ b/packages/server/src/services/deployment.ts @@ -453,6 +453,19 @@ export const createDeploymentSchedule = async ( schedule.compose?.serverId || schedule.server?.serverId; await removeLastTenDeployments(deployment.scheduleId, "schedule", serverId); + await db + .update(deployments) + .set({ + status: "error", + errorMessage: "Superseded by a new run of this schedule.", + finishedAt: new Date().toISOString(), + }) + .where( + and( + eq(deployments.scheduleId, deployment.scheduleId), + eq(deployments.status, "running"), + ), + ); try { const { SCHEDULES_PATH } = paths(!!serverId); const formattedDateTime = format(new Date(), "yyyy-MM-dd:HH:mm:ss"); diff --git a/packages/server/src/utils/startup/cancel-deployments.ts b/packages/server/src/utils/startup/cancel-deployments.ts index 34766c187..8f1272f43 100644 --- a/packages/server/src/utils/startup/cancel-deployments.ts +++ b/packages/server/src/utils/startup/cancel-deployments.ts @@ -1,4 +1,9 @@ -import { applications, compose, deployments } from "@dokploy/server/db/schema"; +import { + applications, + compose, + deployments, + schedules, +} from "@dokploy/server/db/schema"; import { eq, inArray } from "drizzle-orm"; import { db } from "../../db/index"; @@ -6,15 +11,37 @@ export const initCancelDeployments = async () => { try { console.log("Setting up cancel deployments...."); + const runningDeployments = await db + .select({ + deploymentId: deployments.deploymentId, + scheduleId: deployments.scheduleId, + scheduleType: schedules.scheduleType, + }) + .from(deployments) + .leftJoin(schedules, eq(deployments.scheduleId, schedules.scheduleId)) + .where(eq(deployments.status, "running")); + + const deploymentIdsToCancel = runningDeployments + .filter( + (deployment) => + !deployment.scheduleId || + deployment.scheduleType === "dokploy-server", + ) + .map((deployment) => deployment.deploymentId); + + if (deploymentIdsToCancel.length === 0) { + console.log("Cancelled 0 deployments"); + return; + } + const result = await db .update(deployments) .set({ status: "cancelled", }) - .where(eq(deployments.status, "running")) + .where(inArray(deployments.deploymentId, deploymentIdsToCancel)) .returning(); - // Reset the related services so they don't stay stuck in "running". const applicationIds = [ ...new Set( result