Merge pull request #4955 from Dokploy/fix/schedule-run-manually-deployment-metadata
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

fix(schedule): return deployment metadata from runManually and fail early on missing container
This commit is contained in:
Mauricio Siu 2026-08-02 16:22:35 -06:00 committed by GitHub
commit 11e93dde38
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 90 additions and 68 deletions

View File

@ -58,8 +58,12 @@ export const ShowSchedules = ({ id, scheduleType = "application" }: Props) => {
const handleRunManually = async (scheduleId: string) => {
setRunningSchedules((prev) => new Set(prev).add(scheduleId));
try {
await runManually({ scheduleId });
toast.success("Schedule run successfully");
const result = await runManually({ scheduleId });
if (result.status === "error") {
toast.error("Schedule run failed, check the deployment logs");
} else {
toast.success("Schedule run successfully");
}
await refetchSchedules();
} catch {
toast.error("Error running schedule");

View File

@ -329,13 +329,17 @@ export const scheduleRouter = createTRPCRouter({
await checkPermission(ctx, { schedule: ["create"] });
}
try {
await runCommand(input.scheduleId);
const deployment = await runCommand(input.scheduleId);
await audit(ctx, {
action: "run",
resourceType: "schedule",
resourceId: input.scheduleId,
});
return true;
return {
status: deployment.status,
deploymentId: deployment.deploymentId,
logPath: deployment.logPath,
};
} catch (error) {
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",

View File

@ -55,25 +55,46 @@ export const runCommand = async (scheduleId: string) => {
description: "Schedule",
});
if (scheduleType === "application" || scheduleType === "compose") {
let containerId = "";
let serverId = "";
if (scheduleType === "application" && application) {
const container = await getServiceContainer(
application.appName,
application.serverId,
);
containerId = container?.Id || "";
serverId = application.serverId || "";
}
if (scheduleType === "compose" && compose) {
const container = await getComposeContainer(compose, serviceName || "");
containerId = container?.Id || "";
serverId = compose.serverId || "";
}
try {
if (scheduleType === "application" || scheduleType === "compose") {
let containerId = "";
let serverId = "";
if (scheduleType === "application" && application) {
const container = await getServiceContainer(
application.appName,
application.serverId,
);
containerId = container?.Id || "";
serverId = application.serverId || "";
}
if (scheduleType === "compose" && compose) {
const container = await getComposeContainer(compose, serviceName || "");
containerId = container?.Id || "";
serverId = compose.serverId || "";
}
if (serverId) {
try {
if (!containerId) {
const target =
scheduleType === "compose"
? `service '${serviceName}' of compose '${compose?.name}'`
: `application '${application?.appName}'`;
const message = `Container not found for ${target}, make sure the service is running`;
if (serverId) {
await execAsyncRemote(
serverId,
`echo ${quote([`${message}`])} >> ${quote([deployment.logPath])}`,
);
} else {
const writeStream = createWriteStream(deployment.logPath, {
flags: "a",
});
writeStream.write(`${message}\n`);
writeStream.end();
}
throw new Error(message);
}
if (serverId) {
await execAsyncRemote(
serverId,
`
@ -86,47 +107,44 @@ export const runCommand = async (scheduleId: string) => {
echo "✅ Command executed successfully" >> ${quote([deployment.logPath])};
`,
);
} catch (error) {
await updateDeploymentStatus(deployment.deploymentId, "error");
throw error;
}
} else {
const writeStream = createWriteStream(deployment.logPath, { flags: "a" });
} else {
const writeStream = createWriteStream(deployment.logPath, {
flags: "a",
});
try {
if (IS_CLOUD) {
try {
if (IS_CLOUD) {
writeStream.write(
"This feature is not available in the cloud version.",
);
writeStream.end();
return { ...deployment, status: "running" as const };
}
writeStream.write(
"This feature is not available in the cloud version.",
`docker exec ${containerId} ${shellType} -c ${command}\n`,
);
await spawnAsync(
"docker",
["exec", containerId, shellType, "-c", command],
(data) => {
if (writeStream.writable) {
writeStream.write(data);
}
},
);
writeStream.write("✅ Command executed successfully\n");
writeStream.end();
} catch (error) {
writeStream.write("❌ Command failed\n");
writeStream.write(
error instanceof Error ? error.message : "Unknown error",
);
writeStream.end();
return;
throw error;
}
writeStream.write(
`docker exec ${containerId} ${shellType} -c ${command}\n`,
);
await spawnAsync(
"docker",
["exec", containerId, shellType, "-c", command],
(data) => {
if (writeStream.writable) {
writeStream.write(data);
}
},
);
writeStream.write("✅ Command executed successfully\n");
} catch (error) {
writeStream.write("❌ Command failed\n");
writeStream.write(
error instanceof Error ? error.message : "Unknown error",
);
writeStream.end();
await updateDeploymentStatus(deployment.deploymentId, "error");
throw error;
}
}
} else if (scheduleType === "dokploy-server") {
try {
} else if (scheduleType === "dokploy-server") {
const writeStream = createWriteStream(deployment.logPath, { flags: "a" });
const { SCHEDULES_PATH } = paths();
const fullPath = path.join(SCHEDULES_PATH, appName || "");
@ -151,18 +169,13 @@ export const runCommand = async (scheduleId: string) => {
cwd: fullPath,
},
);
} catch (error) {
await updateDeploymentStatus(deployment.deploymentId, "error");
throw error;
}
} else if (scheduleType === "server") {
try {
} else if (scheduleType === "server") {
const { SCHEDULES_PATH } = paths(true);
const fullPath = path.join(SCHEDULES_PATH, appName || "");
const command = `
set -e
echo "Running script" >> ${deployment.logPath};
bash -c ${fullPath}/script.sh 2>&1 | tee -a ${deployment.logPath} || {
bash -c ${fullPath}/script.sh 2>&1 | tee -a ${deployment.logPath} || {
echo "❌ Command failed" >> ${deployment.logPath};
exit 1;
}
@ -177,10 +190,11 @@ export const runCommand = async (scheduleId: string) => {
});
}
});
} catch (error) {
await updateDeploymentStatus(deployment.deploymentId, "error");
throw error;
}
await updateDeploymentStatus(deployment.deploymentId, "done");
return { ...deployment, status: "done" as const };
} catch {
await updateDeploymentStatus(deployment.deploymentId, "error");
return { ...deployment, status: "error" as const };
}
await updateDeploymentStatus(deployment.deploymentId, "done");
};