mirror of
https://github.com/andwati/dokploy.git
synced 2026-11-02 18:22:16 +00:00
Merge pull request #2392 from Dokploy/2341-deployment-functionality-is-totally-broken-on-cloud-version
Integrate Inngest for deployment management in the API. Added Inngest…
This commit is contained in:
@@ -9,6 +9,7 @@
|
|||||||
"typecheck": "tsc --noEmit"
|
"typecheck": "tsc --noEmit"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"inngest": "3.40.1",
|
||||||
"@dokploy/server": "workspace:*",
|
"@dokploy/server": "workspace:*",
|
||||||
"@hono/node-server": "^1.14.3",
|
"@hono/node-server": "^1.14.3",
|
||||||
"@hono/zod-validator": "0.3.0",
|
"@hono/zod-validator": "0.3.0",
|
||||||
|
|||||||
+105
-28
@@ -2,21 +2,79 @@ import { serve } from "@hono/node-server";
|
|||||||
import { Hono } from "hono";
|
import { Hono } from "hono";
|
||||||
import "dotenv/config";
|
import "dotenv/config";
|
||||||
import { zValidator } from "@hono/zod-validator";
|
import { zValidator } from "@hono/zod-validator";
|
||||||
import { Queue } from "@nerimity/mimiqueue";
|
import { Inngest } from "inngest";
|
||||||
import { createClient } from "redis";
|
import { serve as serveInngest } from "inngest/hono";
|
||||||
import { logger } from "./logger.js";
|
import { logger } from "./logger.js";
|
||||||
import { type DeployJob, deployJobSchema } from "./schema.js";
|
import { type DeployJob, deployJobSchema } from "./schema.js";
|
||||||
import { deploy } from "./utils.js";
|
import { deploy } from "./utils.js";
|
||||||
|
|
||||||
const app = new Hono();
|
const app = new Hono();
|
||||||
const redisClient = createClient({
|
|
||||||
url: process.env.REDIS_URL,
|
// Initialize Inngest client
|
||||||
|
export const inngest = new Inngest({
|
||||||
|
id: "dokploy-deployments",
|
||||||
|
name: "Dokploy Deployment Service",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const deploymentFunction = inngest.createFunction(
|
||||||
|
{
|
||||||
|
id: "deploy-application",
|
||||||
|
name: "Deploy Application",
|
||||||
|
concurrency: [
|
||||||
|
{
|
||||||
|
key: "event.data.serverId",
|
||||||
|
limit: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
retries: 1,
|
||||||
|
},
|
||||||
|
{ event: "deployment/requested" },
|
||||||
|
|
||||||
|
async ({ event, step }) => {
|
||||||
|
const jobData = event.data as DeployJob;
|
||||||
|
|
||||||
|
return await step.run("execute-deployment", async () => {
|
||||||
|
logger.info("Deploying started");
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await deploy(jobData);
|
||||||
|
logger.info("Deployment finished", result);
|
||||||
|
|
||||||
|
// Send success event
|
||||||
|
await inngest.send({
|
||||||
|
name: "deployment/completed",
|
||||||
|
data: {
|
||||||
|
...jobData,
|
||||||
|
result,
|
||||||
|
status: "success",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} catch (error) {
|
||||||
|
logger.error("Deployment failed", { jobData, error });
|
||||||
|
|
||||||
|
// Send failure event
|
||||||
|
await inngest.send({
|
||||||
|
name: "deployment/failed",
|
||||||
|
data: {
|
||||||
|
...jobData,
|
||||||
|
error: error instanceof Error ? error.message : String(error),
|
||||||
|
status: "failed",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
app.use(async (c, next) => {
|
app.use(async (c, next) => {
|
||||||
if (c.req.path === "/health") {
|
if (c.req.path === "/health" || c.req.path === "/api/inngest") {
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
const authHeader = c.req.header("X-API-Key");
|
const authHeader = c.req.header("X-API-Key");
|
||||||
|
|
||||||
if (process.env.API_KEY !== authHeader) {
|
if (process.env.API_KEY !== authHeader) {
|
||||||
@@ -26,36 +84,55 @@ app.use(async (c, next) => {
|
|||||||
return next();
|
return next();
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post("/deploy", zValidator("json", deployJobSchema), (c) => {
|
app.post("/deploy", zValidator("json", deployJobSchema), async (c) => {
|
||||||
const data = c.req.valid("json");
|
const data = c.req.valid("json");
|
||||||
queue.add(data, { groupName: data.serverId });
|
logger.info("Received deployment request", data);
|
||||||
return c.json(
|
|
||||||
{
|
try {
|
||||||
message: "Deployment Added",
|
// Send event to Inngest instead of adding to Redis queue
|
||||||
},
|
await inngest.send({
|
||||||
200,
|
name: "deployment/requested",
|
||||||
);
|
data,
|
||||||
|
});
|
||||||
|
|
||||||
|
logger.info("Deployment event sent to Inngest", {
|
||||||
|
serverId: data.serverId,
|
||||||
|
});
|
||||||
|
|
||||||
|
return c.json(
|
||||||
|
{
|
||||||
|
message: "Deployment Added to Inngest Queue",
|
||||||
|
serverId: data.serverId,
|
||||||
|
},
|
||||||
|
200,
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
console.log("error", error);
|
||||||
|
logger.error("Failed to send deployment event", error);
|
||||||
|
return c.json(
|
||||||
|
{
|
||||||
|
message: "Failed to queue deployment",
|
||||||
|
error: error instanceof Error ? error.message : String(error),
|
||||||
|
},
|
||||||
|
500,
|
||||||
|
);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get("/health", async (c) => {
|
app.get("/health", async (c) => {
|
||||||
return c.json({ status: "ok" });
|
return c.json({ status: "ok" });
|
||||||
});
|
});
|
||||||
|
|
||||||
const queue = new Queue({
|
// Serve Inngest functions endpoint
|
||||||
name: "deployments",
|
app.on(
|
||||||
process: async (job: DeployJob) => {
|
["GET", "POST", "PUT"],
|
||||||
logger.info("Deploying job", job);
|
"/api/inngest",
|
||||||
return await deploy(job);
|
serveInngest({
|
||||||
},
|
client: inngest,
|
||||||
redisClient,
|
functions: [deploymentFunction],
|
||||||
});
|
}),
|
||||||
|
);
|
||||||
(async () => {
|
|
||||||
await redisClient.connect();
|
|
||||||
await redisClient.flushAll();
|
|
||||||
logger.info("Redis Cleaned");
|
|
||||||
})();
|
|
||||||
|
|
||||||
const port = Number.parseInt(process.env.PORT || "3000");
|
const port = Number.parseInt(process.env.PORT || "3000");
|
||||||
logger.info("Starting Deployments Server ✅", port);
|
logger.info("Starting Deployments Server with Inngest ✅", port);
|
||||||
serve({ fetch: app.fetch, port });
|
serve({ fetch: app.fetch, port });
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ export const deploy = async (job: DeployJob) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (_) {
|
} catch (e) {
|
||||||
if (job.applicationType === "application") {
|
if (job.applicationType === "application") {
|
||||||
await updateApplicationStatus(job.applicationId, "error");
|
await updateApplicationStatus(job.applicationId, "error");
|
||||||
} else if (job.applicationType === "compose") {
|
} else if (job.applicationType === "compose") {
|
||||||
@@ -76,6 +76,8 @@ export const deploy = async (job: DeployJob) => {
|
|||||||
previewStatus: "error",
|
previewStatus: "error",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
Generated
+1657
-11
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user