Files
dokploy/apps/dokploy/server/api/routers/preview-deployment.ts
Mauricio Siu 24b02f5523 Feat/concurrent deployments in memory queue (#4645)
* feat: add builds concurrency management for servers

- Introduced a new `BuildsConcurrency` component to manage the number of concurrent builds for both local and remote servers, gated by license validity.
- Implemented backend logic to resolve effective builds concurrency based on server settings and organization licenses.
- Added unit tests for concurrency resolution logic to ensure correct behavior under various licensing scenarios.
- Updated database schema to include `buildsConcurrency` field for servers and web server settings.
- Refactored deployment queue to support in-memory job processing with configurable concurrency limits.

This feature enhances deployment flexibility and control for enterprise users.

* refactor: enhance deployment cancellation logic and improve Railpack build isolation

- Reintroduced the `initCancelDeployments` function in the server initialization sequence to ensure deployments can be canceled effectively.
- Updated the Railpack build command to use a unique builder name for each build, preventing conflicts during concurrent deployments.
- Enhanced the cancellation logic to reset application and compose statuses to "idle" after canceling running deployments, improving system reliability.

* test: add buildsConcurrency setting to server configuration tests

- Introduced a new `buildsConcurrency` property in the server configuration tests to ensure proper handling of concurrent builds in deployment scenarios.

* feat: implement builds concurrency management and validation

- Added `assertBuildsConcurrencyAllowed` function to validate concurrency settings based on license status.
- Updated `resolveBuildsConcurrency` to reflect new concurrency limits for free and enterprise tiers.
- Enhanced `BuildsConcurrency` component to manage concurrent builds for servers, with UI adjustments for better user experience.
- Introduced a new settings page for managing concurrent builds across servers, ensuring proper handling of deployments.
- Updated database schema to support increased maximum concurrency values for servers and web server settings.
2026-06-16 23:15:19 -06:00

119 lines
3.4 KiB
TypeScript

import {
findApplicationById,
findPreviewDeploymentById,
findPreviewDeploymentsByApplicationId,
IS_CLOUD,
removePreviewDeployment,
} from "@dokploy/server";
import { checkServicePermissionAndAccess } from "@dokploy/server/services/permission";
import { z } from "zod";
import { audit } from "@/server/api/utils/audit";
import { apiFindAllByApplication } from "@/server/db/schema";
import type { DeploymentJob } from "@/server/queues/queue-types";
import { myQueue } from "@/server/queues/queueSetup";
import { deploy } from "@/server/utils/deploy";
import { createTRPCRouter, protectedProcedure } from "../trpc";
export const previewDeploymentRouter = createTRPCRouter({
all: protectedProcedure
.input(apiFindAllByApplication)
.query(async ({ input, ctx }) => {
await checkServicePermissionAndAccess(ctx, input.applicationId, {
deployment: ["read"],
});
return await findPreviewDeploymentsByApplicationId(input.applicationId);
}),
one: protectedProcedure
.input(z.object({ previewDeploymentId: z.string() }))
.query(async ({ input, ctx }) => {
const previewDeployment = await findPreviewDeploymentById(
input.previewDeploymentId,
);
await checkServicePermissionAndAccess(
ctx,
previewDeployment.applicationId,
{ deployment: ["read"] },
);
return previewDeployment;
}),
delete: protectedProcedure
.input(z.object({ previewDeploymentId: z.string() }))
.mutation(async ({ input, ctx }) => {
const previewDeployment = await findPreviewDeploymentById(
input.previewDeploymentId,
);
await checkServicePermissionAndAccess(
ctx,
previewDeployment.applicationId,
{ deployment: ["cancel"] },
);
await removePreviewDeployment(input.previewDeploymentId);
await audit(ctx, {
action: "delete",
resourceType: "previewDeployment",
resourceId: input.previewDeploymentId,
});
return true;
}),
redeploy: protectedProcedure
.input(
z.object({
previewDeploymentId: z.string(),
title: z.string().optional(),
description: z.string().optional(),
}),
)
.mutation(async ({ input, ctx }) => {
const previewDeployment = await findPreviewDeploymentById(
input.previewDeploymentId,
);
await checkServicePermissionAndAccess(
ctx,
previewDeployment.applicationId,
{ deployment: ["create"] },
);
const application = await findApplicationById(
previewDeployment.applicationId,
);
const jobData: DeploymentJob = {
applicationId: previewDeployment.applicationId,
titleLog: input.title || "Rebuild Preview Deployment",
descriptionLog: input.description || "",
type: "redeploy",
applicationType: "application-preview",
previewDeploymentId: input.previewDeploymentId,
server: !!application.serverId,
serverId: application.serverId ?? undefined,
};
if (IS_CLOUD && application.serverId) {
deploy(jobData).catch((error) => {
console.error("Background deployment failed:", error);
});
await audit(ctx, {
action: "redeploy",
resourceType: "previewDeployment",
resourceId: input.previewDeploymentId,
});
return true;
}
await myQueue.add(
"deployments",
{ ...jobData },
{
removeOnComplete: true,
removeOnFail: true,
},
);
await audit(ctx, {
action: "redeploy",
resourceType: "previewDeployment",
resourceId: input.previewDeploymentId,
});
return true;
}),
});