feat(api): add dockerfile api

This commit is contained in:
Mauricio Siu 2024-09-30 00:27:14 -06:00
parent 06a772e344
commit 2872ef3ccb
9 changed files with 127 additions and 153 deletions

33
Dockerfile.api Normal file
View File

@ -0,0 +1,33 @@
FROM node:18-alpine AS base
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable
FROM base AS build
COPY . /usr/src/app
WORKDIR /usr/src/app
# Install dependencies
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --filter=./apps/api --frozen-lockfile
# Deploy only the dokploy app
ENV NODE_ENV=production
RUN pnpm --filter=./apps/api run build
RUN pnpm --filter=./apps/api --prod deploy /prod/api
RUN cp -R /usr/src/app/apps/api/.dist /prod/api/.dist
FROM base AS dokploy
WORKDIR /app
# Set production
ENV NODE_ENV=production
# Copy only the necessary files
COPY --from=build /prod/api/.dist ./.dist
COPY --from=build /prod/api/package.json ./package.json
COPY --from=build /prod/api/node_modules ./node_modules
CMD HOSTNAME=0.0.0.0 && pnpm start

View File

@ -1,9 +1,11 @@
{
"name": "my-app",
"name": "@dokploy/api",
"version": "0.0.1",
"type": "module",
"scripts": {
"dev": "PORT=4000 tsx watch src/index.ts",
"dev2": "PORT=4001 tsx watch src/index.ts",
"tsc": "tsc --project tsconfig.json"
"build": "tsc --project tsconfig.json",
"start": "node dist/index.js"
},
"dependencies": {
"react": "18.2.0",
@ -13,13 +15,8 @@
"hono": "^4.5.8",
"dotenv": "^16.3.1",
"@upstash/qstash": "2.7.9",
"ioredis": "5.4.1",
"nats": "2.28.2",
"bullmq": "5.13.2",
"@nerimity/mimiqueue": "1.2.3",
"timers": "0.1.1",
"redis": "4.7.0",
"date-fns": "4.1.0"
"@nerimity/mimiqueue": "1.2.3"
},
"devDependencies": {
"typescript": "^5.4.2",

View File

@ -4,7 +4,6 @@ import "dotenv/config";
import { createClient } from "redis";
import { Queue } from "@nerimity/mimiqueue";
import { deployApplication } from "@dokploy/builders";
// import { setTimeout } from "timers/promises";
const app = new Hono();
const redisClient = createClient({
@ -47,7 +46,7 @@ const queue = new Queue({
},
redisClient,
});
const port = process.env.PORT;
const port = Number.parseInt(process.env.PORT || "3000");
(async () => {
await redisClient.connect();
await redisClient.flushAll();

View File

@ -1,82 +1,82 @@
import { Hono } from "hono";
import { Client } from "@upstash/qstash";
import { serve } from "@hono/node-server";
import dotenv from "dotenv";
import Redis from "ioredis";
// import { Hono } from "hono";
// import { Client } from "@upstash/qstash";
// import { serve } from "@hono/node-server";
// import dotenv from "dotenv";
// import Redis from "ioredis";
dotenv.config();
// dotenv.config();
const redis = new Redis({
host: "localhost",
port: 7777,
password: "xlfvpQ0ma2BkkkPX",
});
// const redis = new Redis({
// host: "localhost",
// port: 7777,
// password: "xlfvpQ0ma2BkkkPX",
// });
// redis.set("test", "test");
// console.log(await redis.get("test"));
// // redis.set("test", "test");
// // console.log(await redis.get("test"));
// console.log(await redis.get("user-1-processing"));
const app = new Hono();
console.log("QStash Token:", process.env.PUBLIC_URL);
// // console.log(await redis.get("user-1-processing"));
// const app = new Hono();
// console.log("QStash Token:", process.env.PUBLIC_URL);
const qstash = new Client({
token: process.env.QSTASH_TOKEN as string,
});
// const qstash = new Client({
// token: process.env.QSTASH_TOKEN as string,
// });
const queue = qstash.queue({
queueName: "deployments",
});
// const queue = qstash.queue({
// queueName: "deployments",
// });
// Endpoint que publica un mensaje en QStash
app.post("/enqueue", async (c) => {
const { userId, deploymentId } = await c.req.json();
const response = await qstash.publishJSON({
url: `${process.env.PUBLIC_URL}/process`, // Endpoint para procesar la tarea
body: { userId, deploymentId }, // Datos del despliegue
});
// // Endpoint que publica un mensaje en QStash
// app.post("/enqueue", async (c) => {
// const { userId, deploymentId } = await c.req.json();
// const response = await qstash.publishJSON({
// url: `${process.env.PUBLIC_URL}/process`, // Endpoint para procesar la tarea
// body: { userId, deploymentId }, // Datos del despliegue
return c.json({ message: "Task enqueued", id: response.messageId });
});
// });
// Endpoint que recibe el mensaje procesado
app.post("/process", async (c) => {
const { userId, deploymentId } = await c.req.json();
// return c.json({ message: "Task enqueued", id: response.messageId });
// });
const isProcessing = await redis.get(`user-${userId}-processing`);
console.log(`isProcessing for user ${userId}:`, isProcessing);
// // Endpoint que recibe el mensaje procesado
// app.post("/process", async (c) => {
// const { userId, deploymentId } = await c.req.json();
if (isProcessing === "true") {
console.log(
`User ${userId} is already processing a deployment. Queuing the next one.`,
);
return c.json(
{
status: "User is already processing a deployment, waiting...",
},
{
status: 400,
},
);
}
redis.set(`user-${userId}-processing`, "true");
// const isProcessing = await redis.get(`user-${userId}-processing`);
// console.log(`isProcessing for user ${userId}:`, isProcessing);
try {
await new Promise((resolve) => setTimeout(resolve, 5000));
} catch (error) {
} finally {
await redis.del(`user-${userId}-processing`);
}
// if (isProcessing === "true") {
// console.log(
// `User ${userId} is already processing a deployment. Queuing the next one.`,
// );
// return c.json(
// {
// status: "User is already processing a deployment, waiting...",
// },
// {
// status: 400,
// },
// );
// }
// redis.set(`user-${userId}-processing`, "true");
return c.json({ status: "Processed", userId, deploymentId });
});
// try {
// await new Promise((resolve) => setTimeout(resolve, 5000));
// } catch (error) {
// } finally {
// await redis.del(`user-${userId}-processing`);
// }
// Inicia el servidor en el puerto 3000
const port = 3000;
console.log(`Server is running on port http://localhost:${port}`);
// return c.json({ status: "Processed", userId, deploymentId });
// });
serve({
fetch: app.fetch,
port,
});
// 18
// // Inicia el servidor en el puerto 3000
// const port = 3000;
// console.log(`Server is running on port http://localhost:${port}`);
// serve({
// fetch: app.fetch,
// port,
// });
// // 18

View File

@ -1,6 +1,8 @@
import { LEMON_SQUEEZY_API_KEY, LEMON_SQUEEZY_STORE_ID } from ".";
// import { LEMON_SQUEEZY_API_KEY, LEMON_SQUEEZY_STORE_ID } from ".";
import type { LemonSqueezyLicenseResponse } from "./types";
const LEMON_SQUEEZY_API_KEY = process.env.LEMON_SQUEEZY_API_KEY;
const LEMON_SQUEEZY_STORE_ID = process.env.LEMON_SQUEEZY_STORE_ID;
export const validateLemonSqueezyLicense = async (
licenseKey: string,
): Promise<LemonSqueezyLicenseResponse> => {

View File

@ -5,10 +5,9 @@
"moduleResolution": "Node",
"strict": true,
"skipLibCheck": true,
"types": ["node"],
"outDir": "dist",
"jsx": "react-jsx",
"jsxImportSource": "hono/jsx",
"traceResolution": true,
"diagnostics": true
}
"jsxImportSource": "hono/jsx"
},
"exclude": ["node_modules", "dist"]
}

View File

@ -14,6 +14,7 @@ import {
initializeTraefik,
initCronJobs,
sendDokployRestartNotifications,
IS_CLOUD,
} from "@dokploy/builders";
import { setupDockerContainerLogsWebSocketServer } from "./wss/docker-container-logs";
import { setupDockerContainerTerminalWebSocketServer } from "./wss/docker-container-terminal";
@ -42,9 +43,7 @@ void app.prepare().then(async () => {
setupTerminalWebSocketServer(server);
setupDockerStatsMonitoringSocketServer(server);
if (process.env.NODE_ENV === "production") {
setupDirectories();
createDefaultMiddlewares();
if (process.env.NODE_ENV === "production" && !IS_CLOUD) {
setupDirectories();
createDefaultMiddlewares();
await initializeNetwork();
@ -63,9 +62,16 @@ void app.prepare().then(async () => {
await sendDokployRestartNotifications();
}
if (IS_CLOUD) {
await migration();
}
server.listen(PORT);
console.log("Server Started:", PORT);
deploymentWorker.run();
if (!IS_CLOUD) {
deploymentWorker.run();
}
} catch (e) {
console.error("Main Server Error", e);
}

View File

@ -1,5 +1,4 @@
import { build } from "esbuild";
import TsconfigPathsPlugin from "@esbuild-plugins/tsconfig-paths";
import path from "node:path";
build({

View File

@ -54,24 +54,12 @@ importers:
'@upstash/qstash':
specifier: 2.7.9
version: 2.7.9
bullmq:
specifier: 5.13.2
version: 5.13.2
date-fns:
specifier: 4.1.0
version: 4.1.0
dotenv:
specifier: ^16.3.1
version: 16.4.5
hono:
specifier: ^4.5.8
version: 4.5.8
ioredis:
specifier: 5.4.1
version: 5.4.1
nats:
specifier: 2.28.2
version: 2.28.2
react:
specifier: 18.2.0
version: 18.2.0
@ -81,9 +69,6 @@ importers:
redis:
specifier: 4.7.0
version: 4.7.0
timers:
specifier: 0.1.1
version: 0.1.1
devDependencies:
'@types/node':
specifier: ^20.11.17
@ -4023,9 +4008,6 @@ packages:
resolution: {integrity: sha512-8f9ZJCUXyT1M35Jx7MkBgmBMo3oHTTBIPLiY9xyL0pl3T5RwcPEY8cUHr5LBNfu/fk6c2T4DJZuVM/8ZZT2D2A==}
engines: {node: '>=10.0.0'}
bullmq@5.13.2:
resolution: {integrity: sha512-McGE8k3mrCvdUHdU0sHkTKDS1xr4pff+hbEKBY51wk5S6Za0gkuejYA620VQTo3Zz37E/NVWMgumwiXPQ3yZcA==}
bullmq@5.4.2:
resolution: {integrity: sha512-dkR/KGUw18miLe3QWtvSlmGvEe08aZF+w1jZyqEHMWFW3RP4162qp6OGud0/QCAOjusiRI8UOxUhbnortPY+rA==}
@ -4449,9 +4431,6 @@ packages:
date-fns@3.6.0:
resolution: {integrity: sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==}
date-fns@4.1.0:
resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==}
debug@3.2.7:
resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
peerDependencies:
@ -6502,10 +6481,6 @@ packages:
napi-build-utils@1.0.2:
resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==}
nats@2.28.2:
resolution: {integrity: sha512-02cvR8EPach+0BfVaQjPgsbPFn6uMjEQAuvXS2ppg8jiWEm2KYdfmeFmtshiU9b2+kFh3LSEKMEaIfRgk3K8tw==}
engines: {node: '>= 14.0.0'}
natural-compare@1.4.0:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
@ -6574,10 +6549,6 @@ packages:
sass:
optional: true
nkeys.js@1.1.0:
resolution: {integrity: sha512-tB/a0shZL5UZWSwsoeyqfTszONTt4k2YS0tuQioMOD180+MbombYVgzDUYHlx+gejYK6rgf08n/2Df99WY0Sxg==}
engines: {node: '>=10.0.0'}
node-abi@3.65.0:
resolution: {integrity: sha512-ThjYBfoDNr08AWx6hGaRbfPwxKV9kVzAzOzlLKbk2CuqXE2xnCh+cbAGnwM3t8Lq4v9rUB7VfondlkBckcJrVA==}
engines: {node: '>=10'}
@ -7870,9 +7841,6 @@ packages:
resolution: {integrity: sha512-wFH7+SEAcKfJpfLPkrgMPvvwnEtj8W4IurvEyrKsDleXnKLCDw71w8jltvfLa8Rm4qQxxT4jmDBYbJG/z7qoww==}
engines: {node: '>=0.12'}
timers@0.1.1:
resolution: {integrity: sha512-pkJC8uIP/gxDHxNQUBUbjHyl6oZfT+ofn7tbaHW+CFIUjI+Q2MBbHcx1JSBQfhDaTcO9bNg328q0i7Vk5PismQ==}
tiny-invariant@1.3.3:
resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==}
@ -7995,9 +7963,6 @@ packages:
tweetnacl@0.14.5:
resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==}
tweetnacl@1.0.3:
resolution: {integrity: sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==}
type-check@0.4.0:
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
engines: {node: '>= 0.8.0'}
@ -12228,18 +12193,6 @@ snapshots:
buildcheck@0.0.6:
optional: true
bullmq@5.13.2:
dependencies:
cron-parser: 4.9.0
ioredis: 5.4.1
msgpackr: 1.11.0
node-abort-controller: 3.1.1
semver: 7.6.2
tslib: 2.6.3
uuid: 9.0.1
transitivePeerDependencies:
- supports-color
bullmq@5.4.2:
dependencies:
cron-parser: 4.9.0
@ -12658,8 +12611,6 @@ snapshots:
date-fns@3.6.0: {}
date-fns@4.1.0: {}
debug@3.2.7:
dependencies:
ms: 2.1.3
@ -13252,7 +13203,7 @@ snapshots:
eslint: 8.45.0
eslint-import-resolver-node: 0.3.9
eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.1.6))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.45.0))(eslint@8.45.0)
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.1.6))(eslint-import-resolver-typescript@3.6.1)(eslint@8.45.0)
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.1.6))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.1.6))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.45.0))(eslint@8.45.0))(eslint@8.45.0)
eslint-plugin-jsx-a11y: 6.9.0(eslint@8.45.0)
eslint-plugin-react: 7.35.0(eslint@8.45.0)
eslint-plugin-react-hooks: 5.0.0-canary-7118f5dd7-20230705(eslint@8.45.0)
@ -13276,7 +13227,7 @@ snapshots:
enhanced-resolve: 5.17.1
eslint: 8.45.0
eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.1.6))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.1.6))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.45.0))(eslint@8.45.0))(eslint@8.45.0)
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.1.6))(eslint-import-resolver-typescript@3.6.1)(eslint@8.45.0)
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.1.6))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.1.6))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.45.0))(eslint@8.45.0))(eslint@8.45.0)
fast-glob: 3.3.2
get-tsconfig: 4.7.5
is-core-module: 2.15.0
@ -13298,7 +13249,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.1.6))(eslint-import-resolver-typescript@3.6.1)(eslint@8.45.0):
eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.1.6))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.1.6))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.45.0))(eslint@8.45.0))(eslint@8.45.0):
dependencies:
array-includes: 3.1.8
array.prototype.findlastindex: 1.2.5
@ -15199,10 +15150,6 @@ snapshots:
napi-build-utils@1.0.2:
optional: true
nats@2.28.2:
dependencies:
nkeys.js: 1.1.0
natural-compare@1.4.0: {}
negotiator@0.6.3: {}
@ -15305,10 +15252,6 @@ snapshots:
- '@babel/core'
- babel-plugin-macros
nkeys.js@1.1.0:
dependencies:
tweetnacl: 1.0.3
node-abi@3.65.0:
dependencies:
semver: 7.6.2
@ -16750,8 +16693,6 @@ snapshots:
es5-ext: 0.10.64
next-tick: 1.1.0
timers@0.1.1: {}
tiny-invariant@1.3.3: {}
tinybench@2.8.0: {}
@ -16871,8 +16812,6 @@ snapshots:
tweetnacl@0.14.5: {}
tweetnacl@1.0.3: {}
type-check@0.4.0:
dependencies:
prelude-ls: 1.2.1