diff --git a/apps/dokploy/pages/api/deploy/[refreshToken].ts b/apps/dokploy/pages/api/deploy/[refreshToken].ts index 415ece29bd..9081846312 100644 --- a/apps/dokploy/pages/api/deploy/[refreshToken].ts +++ b/apps/dokploy/pages/api/deploy/[refreshToken].ts @@ -5,6 +5,7 @@ import { shouldDeploy, } from "@dokploy/server"; import { eq } from "drizzle-orm"; +import { nanoid } from "nanoid"; import type { NextApiRequest, NextApiResponse } from "next"; import { db } from "@/server/db"; import { applications } from "@/server/db/schema"; @@ -231,6 +232,7 @@ export default async function handler( } try { + const jobId = nanoid(); const jobData: DeploymentJob = { applicationId: application.applicationId as string, titleLog: deploymentTitle, @@ -238,6 +240,7 @@ export default async function handler( type: "deploy", applicationType: "application", server: !!application.serverId, + jobId, }; if (IS_CLOUD && application.serverId) { diff --git a/apps/dokploy/pages/api/deploy/compose/[refreshToken].ts b/apps/dokploy/pages/api/deploy/compose/[refreshToken].ts index d9b5ef2a2a..e3481b5df5 100644 --- a/apps/dokploy/pages/api/deploy/compose/[refreshToken].ts +++ b/apps/dokploy/pages/api/deploy/compose/[refreshToken].ts @@ -1,5 +1,6 @@ import { IS_CLOUD, shouldDeploy } from "@dokploy/server"; import { eq } from "drizzle-orm"; +import { nanoid } from "nanoid"; import type { NextApiRequest, NextApiResponse } from "next"; import { db } from "@/server/db"; import { compose } from "@/server/db/schema"; @@ -168,6 +169,7 @@ export default async function handler( } try { + const jobId = nanoid(); const jobData: DeploymentJob = { composeId: composeResult.composeId as string, titleLog: deploymentTitle, @@ -175,6 +177,7 @@ export default async function handler( applicationType: "compose", descriptionLog: `Hash: ${deploymentHash}`, server: !!composeResult.serverId, + jobId, }; if (IS_CLOUD && composeResult.serverId) { diff --git a/apps/dokploy/pages/api/deploy/github.ts b/apps/dokploy/pages/api/deploy/github.ts index 9369e800ef..bdcdfb003e 100644 --- a/apps/dokploy/pages/api/deploy/github.ts +++ b/apps/dokploy/pages/api/deploy/github.ts @@ -11,6 +11,7 @@ import { } from "@dokploy/server"; import { Webhooks } from "@octokit/webhooks"; import { and, eq } from "drizzle-orm"; +import { nanoid } from "nanoid"; import type { NextApiRequest, NextApiResponse } from "next"; import { db } from "@/server/db"; import { applications, compose, github } from "@/server/db/schema"; @@ -117,6 +118,7 @@ export default async function handler( }); for (const app of apps) { + const jobId = nanoid(); const jobData: DeploymentJob = { applicationId: app.applicationId as string, titleLog: deploymentTitle, @@ -124,6 +126,7 @@ export default async function handler( type: "deploy", applicationType: "application", server: !!app.serverId, + jobId, }; if (IS_CLOUD && app.serverId) { @@ -156,6 +159,7 @@ export default async function handler( }); for (const composeApp of composeApps) { + const jobId = nanoid(); const jobData: DeploymentJob = { composeId: composeApp.composeId as string, titleLog: deploymentTitle, @@ -163,6 +167,7 @@ export default async function handler( applicationType: "compose", descriptionLog: `Hash: ${deploymentHash}`, server: !!composeApp.serverId, + jobId, }; if (IS_CLOUD && composeApp.serverId) { @@ -230,6 +235,7 @@ export default async function handler( }); for (const app of apps) { + const jobId = nanoid(); const jobData: DeploymentJob = { applicationId: app.applicationId as string, titleLog: deploymentTitle, @@ -237,6 +243,7 @@ export default async function handler( type: "deploy", applicationType: "application", server: !!app.serverId, + jobId, }; const shouldDeployPaths = shouldDeploy( @@ -278,6 +285,7 @@ export default async function handler( }); for (const composeApp of composeApps) { + const jobId = nanoid(); const jobData: DeploymentJob = { composeId: composeApp.composeId as string, titleLog: deploymentTitle, @@ -285,6 +293,7 @@ export default async function handler( applicationType: "compose", descriptionLog: `Hash: ${deploymentHash}`, server: !!composeApp.serverId, + jobId, }; const shouldDeployPaths = shouldDeploy( @@ -487,6 +496,7 @@ export default async function handler( previewDeploymentId = previewDeployment.previewDeploymentId; } + const jobId = nanoid(); const jobData: DeploymentJob = { applicationId: app.applicationId as string, titleLog: "Preview Deployment", @@ -495,6 +505,7 @@ export default async function handler( applicationType: "application-preview", server: !!app.serverId, previewDeploymentId, + jobId, }; if (IS_CLOUD && app.serverId) { diff --git a/apps/dokploy/server/api/routers/application.ts b/apps/dokploy/server/api/routers/application.ts index c0666fcc78..85aa21d11a 100644 --- a/apps/dokploy/server/api/routers/application.ts +++ b/apps/dokploy/server/api/routers/application.ts @@ -325,6 +325,7 @@ export const applicationRouter = createTRPCRouter({ message: "You are not authorized to redeploy this application", }); } + const jobId = nanoid(); const jobData: DeploymentJob = { applicationId: input.applicationId, titleLog: input.title || "Rebuild deployment", @@ -332,6 +333,7 @@ export const applicationRouter = createTRPCRouter({ type: "redeploy", applicationType: "application", server: !!application.serverId, + jobId, }; if (IS_CLOUD && application.serverId) { @@ -339,7 +341,7 @@ export const applicationRouter = createTRPCRouter({ deploy(jobData).catch((error) => { console.error("Background deployment failed:", error); }); - return true; + return { jobId }; } await myQueue.add( "deployments", @@ -349,6 +351,7 @@ export const applicationRouter = createTRPCRouter({ removeOnFail: true, }, ); + return { jobId }; }), saveEnvironment: protectedProcedure .input(apiSaveEnvironmentVariables) @@ -693,6 +696,7 @@ export const applicationRouter = createTRPCRouter({ message: "You are not authorized to deploy this application", }); } + const jobId = nanoid(); const jobData: DeploymentJob = { applicationId: input.applicationId, titleLog: input.title || "Manual deployment", @@ -700,6 +704,7 @@ export const applicationRouter = createTRPCRouter({ type: "deploy", applicationType: "application", server: !!application.serverId, + jobId, }; if (IS_CLOUD && application.serverId) { jobData.serverId = application.serverId; @@ -707,7 +712,7 @@ export const applicationRouter = createTRPCRouter({ console.error("Background deployment failed:", error); }); - return true; + return { jobId }; } await myQueue.add( "deployments", @@ -717,6 +722,7 @@ export const applicationRouter = createTRPCRouter({ removeOnFail: true, }, ); + return { jobId }; }), cleanQueues: protectedProcedure diff --git a/apps/dokploy/server/api/routers/compose.ts b/apps/dokploy/server/api/routers/compose.ts index 4ad2ca00a0..d69e681f0a 100644 --- a/apps/dokploy/server/api/routers/compose.ts +++ b/apps/dokploy/server/api/routers/compose.ts @@ -406,6 +406,7 @@ export const composeRouter = createTRPCRouter({ message: "You are not authorized to deploy this compose", }); } + const jobId = nanoid(); const jobData: DeploymentJob = { composeId: input.composeId, titleLog: input.title || "Manual deployment", @@ -413,6 +414,7 @@ export const composeRouter = createTRPCRouter({ applicationType: "compose", descriptionLog: input.description || "", server: !!compose.serverId, + jobId, }; if (IS_CLOUD && compose.serverId) { @@ -420,7 +422,7 @@ export const composeRouter = createTRPCRouter({ deploy(jobData).catch((error) => { console.error("Background deployment failed:", error); }); - return true; + return { jobId }; } await myQueue.add( "deployments", @@ -430,7 +432,7 @@ export const composeRouter = createTRPCRouter({ removeOnFail: true, }, ); - return { success: true, message: "Deployment queued" }; + return { jobId }; }), redeploy: protectedProcedure .input(apiRedeployCompose) @@ -445,6 +447,7 @@ export const composeRouter = createTRPCRouter({ message: "You are not authorized to redeploy this compose", }); } + const jobId = nanoid(); const jobData: DeploymentJob = { composeId: input.composeId, titleLog: input.title || "Rebuild deployment", @@ -452,13 +455,14 @@ export const composeRouter = createTRPCRouter({ applicationType: "compose", descriptionLog: input.description || "", server: !!compose.serverId, + jobId, }; if (IS_CLOUD && compose.serverId) { jobData.serverId = compose.serverId; deploy(jobData).catch((error) => { console.error("Background deployment failed:", error); }); - return true; + return { jobId }; } await myQueue.add( "deployments", @@ -468,7 +472,7 @@ export const composeRouter = createTRPCRouter({ removeOnFail: true, }, ); - return { success: true, message: "Redeployment queued" }; + return { jobId }; }), stop: protectedProcedure .input(apiFindCompose) diff --git a/apps/dokploy/server/queues/deployments-queue.ts b/apps/dokploy/server/queues/deployments-queue.ts index 4c117e7e33..863204b3e2 100644 --- a/apps/dokploy/server/queues/deployments-queue.ts +++ b/apps/dokploy/server/queues/deployments-queue.ts @@ -24,12 +24,14 @@ export const deploymentWorker = new Worker( applicationId: job.data.applicationId, titleLog: job.data.titleLog, descriptionLog: job.data.descriptionLog, + jobId: job.data.jobId, }); } else if (job.data.type === "deploy") { await deployApplication({ applicationId: job.data.applicationId, titleLog: job.data.titleLog, descriptionLog: job.data.descriptionLog, + jobId: job.data.jobId, }); } } else if (job.data.applicationType === "compose") { @@ -41,12 +43,14 @@ export const deploymentWorker = new Worker( composeId: job.data.composeId, titleLog: job.data.titleLog, descriptionLog: job.data.descriptionLog, + jobId: job.data.jobId, }); } else if (job.data.type === "redeploy") { await rebuildCompose({ composeId: job.data.composeId, titleLog: job.data.titleLog, descriptionLog: job.data.descriptionLog, + jobId: job.data.jobId, }); } } else if (job.data.applicationType === "application-preview") { @@ -60,6 +64,7 @@ export const deploymentWorker = new Worker( titleLog: job.data.titleLog, descriptionLog: job.data.descriptionLog, previewDeploymentId: job.data.previewDeploymentId, + jobId: job.data.jobId, }); } } diff --git a/apps/dokploy/server/queues/queue-types.ts b/apps/dokploy/server/queues/queue-types.ts index ef8df6943b..0232476221 100644 --- a/apps/dokploy/server/queues/queue-types.ts +++ b/apps/dokploy/server/queues/queue-types.ts @@ -7,6 +7,7 @@ type DeployJob = type: "deploy" | "redeploy"; applicationType: "application"; serverId?: string; + jobId?: string; } | { composeId: string; @@ -16,6 +17,7 @@ type DeployJob = type: "deploy" | "redeploy"; applicationType: "compose"; serverId?: string; + jobId?: string; } | { applicationId: string; @@ -26,6 +28,7 @@ type DeployJob = applicationType: "application-preview"; previewDeploymentId: string; serverId?: string; + jobId?: string; }; export type DeploymentJob = DeployJob; diff --git a/packages/server/src/services/application.ts b/packages/server/src/services/application.ts index 61a77ae5aa..73d2716dad 100644 --- a/packages/server/src/services/application.ts +++ b/packages/server/src/services/application.ts @@ -167,10 +167,12 @@ export const deployApplication = async ({ applicationId, titleLog = "Manual deployment", descriptionLog = "", + jobId, }: { applicationId: string; titleLog: string; descriptionLog: string; + jobId?: string; }) => { const application = await findApplicationById(applicationId); const serverId = application.buildServerId || application.serverId; @@ -180,6 +182,7 @@ export const deployApplication = async ({ applicationId: applicationId, title: titleLog, description: descriptionLog, + jobId, }); try { @@ -270,10 +273,12 @@ export const rebuildApplication = async ({ applicationId, titleLog = "Rebuild deployment", descriptionLog = "", + jobId, }: { applicationId: string; titleLog: string; descriptionLog: string; + jobId?: string; }) => { const application = await findApplicationById(applicationId); const serverId = application.buildServerId || application.serverId; @@ -283,6 +288,7 @@ export const rebuildApplication = async ({ applicationId: applicationId, title: titleLog, description: descriptionLog, + jobId, }); try { @@ -337,11 +343,13 @@ export const deployPreviewApplication = async ({ titleLog = "Preview Deployment", descriptionLog = "", previewDeploymentId, + jobId, }: { applicationId: string; titleLog: string; descriptionLog: string; previewDeploymentId: string; + jobId?: string; }) => { const application = await findApplicationById(applicationId); @@ -349,6 +357,7 @@ export const deployPreviewApplication = async ({ title: titleLog, description: descriptionLog, previewDeploymentId: previewDeploymentId, + jobId, }); const previewDeployment = diff --git a/packages/server/src/services/compose.ts b/packages/server/src/services/compose.ts index 89a12a1564..c4eea5ab04 100644 --- a/packages/server/src/services/compose.ts +++ b/packages/server/src/services/compose.ts @@ -205,10 +205,12 @@ export const deployCompose = async ({ composeId, titleLog = "Manual deployment", descriptionLog = "", + jobId, }: { composeId: string; titleLog: string; descriptionLog: string; + jobId?: string; }) => { const compose = await findComposeById(composeId); @@ -219,6 +221,7 @@ export const deployCompose = async ({ composeId: composeId, title: titleLog, description: descriptionLog, + jobId, }); try { @@ -321,10 +324,12 @@ export const rebuildCompose = async ({ composeId, titleLog = "Rebuild deployment", descriptionLog = "", + jobId, }: { composeId: string; titleLog: string; descriptionLog: string; + jobId?: string; }) => { const compose = await findComposeById(composeId); @@ -332,6 +337,7 @@ export const rebuildCompose = async ({ composeId: composeId, title: titleLog, description: descriptionLog, + jobId, }); try { diff --git a/packages/server/src/services/deployment.ts b/packages/server/src/services/deployment.ts index 6244ec8eb6..3e21e8af08 100644 --- a/packages/server/src/services/deployment.ts +++ b/packages/server/src/services/deployment.ts @@ -71,7 +71,7 @@ export const createDeployment = async ( deployment: Omit< typeof apiCreateDeployment._type, "deploymentId" | "createdAt" | "status" | "logPath" - >, + > & { jobId?: string }, ) => { const application = await findApplicationById(deployment.applicationId); try { @@ -107,6 +107,7 @@ export const createDeployment = async ( const deploymentCreate = await db .insert(deployments) .values({ + ...(deployment.jobId && { deploymentId: deployment.jobId }), applicationId: deployment.applicationId, title: deployment.title || "Deployment", status: "running", @@ -152,7 +153,7 @@ export const createDeploymentPreview = async ( deployment: Omit< typeof apiCreateDeploymentPreview._type, "deploymentId" | "createdAt" | "status" | "logPath" - >, + > & { jobId?: string }, ) => { const previewDeployment = await findPreviewDeploymentById( deployment.previewDeploymentId, @@ -191,6 +192,7 @@ export const createDeploymentPreview = async ( const deploymentCreate = await db .insert(deployments) .values({ + ...(deployment.jobId && { deploymentId: deployment.jobId }), title: deployment.title || "Deployment", status: "running", logPath: logFilePath, @@ -235,7 +237,7 @@ export const createDeploymentCompose = async ( deployment: Omit< typeof apiCreateDeploymentCompose._type, "deploymentId" | "createdAt" | "status" | "logPath" - >, + > & { jobId?: string }, ) => { const compose = await findComposeById(deployment.composeId); try { @@ -268,6 +270,7 @@ echo "Initializing deployment\n" >> ${logFilePath}; const deploymentCreate = await db .insert(deployments) .values({ + ...(deployment.jobId && { deploymentId: deployment.jobId }), composeId: deployment.composeId, title: deployment.title || "Deployment", description: deployment.description || "",