diff --git a/README.md b/README.md index 8faf22a35..d60962cff 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,10 @@ For detailed documentation, visit [docs.dokploy.com](https://docs.dokploy.com).
diff --git a/apps/api/src/index.ts b/apps/api/src/index.ts index aa7358335..8ddb56dec 100644 --- a/apps/api/src/index.ts +++ b/apps/api/src/index.ts @@ -5,7 +5,11 @@ import { zValidator } from "@hono/zod-validator"; import { Inngest } from "inngest"; import { serve as serveInngest } from "inngest/hono"; import { logger } from "./logger.js"; -import { type DeployJob, deployJobSchema } from "./schema.js"; +import { + cancelDeploymentSchema, + type DeployJob, + deployJobSchema, +} from "./schema.js"; import { deploy } from "./utils.js"; const app = new Hono(); @@ -27,6 +31,13 @@ export const deploymentFunction = inngest.createFunction( }, ], retries: 0, + cancelOn: [ + { + event: "deployment/cancelled", + if: "async.data.applicationId == event.data.applicationId || async.data.composeId == event.data.composeId", + timeout: "1h", // Allow cancellation for up to 1 hour + }, + ], }, { event: "deployment/requested" }, @@ -119,6 +130,48 @@ app.post("/deploy", zValidator("json", deployJobSchema), async (c) => { } }); +app.post( + "/cancel-deployment", + zValidator("json", cancelDeploymentSchema), + async (c) => { + const data = c.req.valid("json"); + logger.info("Received cancel deployment request", data); + + try { + // Send cancellation event to Inngest + + await inngest.send({ + name: "deployment/cancelled", + data, + }); + + const identifier = + data.applicationType === "application" + ? `applicationId: ${data.applicationId}` + : `composeId: ${data.composeId}`; + + logger.info("Deployment cancellation event sent", { + ...data, + identifier, + }); + + return c.json({ + message: "Deployment cancellation requested", + applicationType: data.applicationType, + }); + } catch (error) { + logger.error("Failed to send deployment cancellation event", error); + return c.json( + { + message: "Failed to cancel deployment", + error: error instanceof Error ? error.message : String(error), + }, + 500, + ); + } + }, +); + app.get("/health", async (c) => { return c.json({ status: "ok" }); }); diff --git a/apps/api/src/schema.ts b/apps/api/src/schema.ts index 609289bf7..5a4355956 100644 --- a/apps/api/src/schema.ts +++ b/apps/api/src/schema.ts @@ -3,8 +3,8 @@ import { z } from "zod"; export const deployJobSchema = z.discriminatedUnion("applicationType", [ z.object({ applicationId: z.string(), - titleLog: z.string(), - descriptionLog: z.string(), + titleLog: z.string().optional(), + descriptionLog: z.string().optional(), server: z.boolean().optional(), type: z.enum(["deploy", "redeploy"]), applicationType: z.literal("application"), @@ -12,8 +12,8 @@ export const deployJobSchema = z.discriminatedUnion("applicationType", [ }), z.object({ composeId: z.string(), - titleLog: z.string(), - descriptionLog: z.string(), + titleLog: z.string().optional(), + descriptionLog: z.string().optional(), server: z.boolean().optional(), type: z.enum(["deploy", "redeploy"]), applicationType: z.literal("compose"), @@ -22,8 +22,8 @@ export const deployJobSchema = z.discriminatedUnion("applicationType", [ z.object({ applicationId: z.string(), previewDeploymentId: z.string(), - titleLog: z.string(), - descriptionLog: z.string(), + titleLog: z.string().optional(), + descriptionLog: z.string().optional(), server: z.boolean().optional(), type: z.enum(["deploy"]), applicationType: z.literal("application-preview"), @@ -32,3 +32,16 @@ export const deployJobSchema = z.discriminatedUnion("applicationType", [ ]); export type DeployJob = z.infer
+
+ {`Enter duration in nanoseconds:
+ • 30000000000 - 30 seconds
+ • 120000000000 - 2 minutes
+ • 3600000000000 - 1 hour
+ • 0 - no grace period`}
+
+
+ +++
+
+ {`{
+ Mode?: string | undefined;
+ Ports?: Array<{
+ Protocol?: string | undefined;
+ TargetPort?: number | undefined;
+ PublishedPort?: number | undefined;
+ PublishMode?: string | undefined;
+ }> | undefined;
+}`}
+
+
+ +++