fix: don't cancel schedule deployments running outside the panel process on restart (#5053)
Some checks are pending
Auto PR to main when version changes / create-pr (push) Waiting to run
Build Docker images / build-and-push-cloud-image (push) Waiting to run
Build Docker images / build-and-push-schedule-image (push) Waiting to run
Build Docker images / build-and-push-server-image (push) Waiting to run
Dokploy Docker Build / docker-amd (push) Waiting to run
Dokploy Docker Build / docker-arm (push) Waiting to run
Dokploy Docker Build / combine-manifests (push) Blocked by required conditions
Dokploy Docker Build / generate-release (push) Blocked by required conditions
Dokploy Docker Build / sync-version (push) Blocked by required conditions
autofix.ci / format (push) Waiting to run
Dokploy Monitoring Build / docker-amd (push) Waiting to run
Dokploy Monitoring Build / docker-arm (push) Waiting to run
Dokploy Monitoring Build / combine-manifests (push) Blocked by required conditions
Generate and Sync OpenAPI / Generate OpenAPI and commit to Dokploy repo (push) Waiting to run

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.
This commit is contained in:
Mauricio Siu 2026-08-11 21:33:49 -06:00 committed by GitHub
parent 3cad115155
commit f12ecc3350
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 43 additions and 3 deletions

View File

@ -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");

View File

@ -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