Merge pull request #423 from Dokploy/refactor/requests

Refactor/requests
This commit is contained in:
Mauricio Siu 2024-09-06 22:48:26 -06:00 committed by GitHub
commit 7bdb572f91
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 163 additions and 34 deletions

View File

@ -1,3 +1,4 @@
import { DialogAction } from "@/components/shared/dialog-action";
import { Button } from "@/components/ui/button";
import {
Card,
@ -20,9 +21,13 @@ export const ShowRequests = () => {
const { data: isLogRotateActive, refetch: refetchLogRotate } =
api.settings.getLogRotateStatus.useQuery();
const { mutateAsync } = api.settings.activateLogRotate.useMutation();
const { mutateAsync: deactivateLogRotate } =
api.settings.deactivateLogRotate.useMutation();
const { mutateAsync: toggleLogRotate } =
api.settings.toggleLogRotate.useMutation();
const { data: isActive, refetch } =
api.settings.haveActivateRequests.useQuery();
const { mutateAsync: toggleRequests } =
api.settings.toggleRequests.useMutation();
return (
<>
@ -33,29 +38,45 @@ export const ShowRequests = () => {
<CardDescription>
<span>Showing web and API requests over time</span>
</CardDescription>
{!isLogRotateActive && (
<Button
onClick={() => {
mutateAsync()
<div className="flex w-fit gap-4">
<DialogAction
title={isActive ? "Deactivate Requests" : "Activate Requests"}
description="You will also need to restart Traefik to apply the changes"
onClick={async () => {
await toggleRequests({ enable: !isActive })
.then(() => {
toast.success("Log rotate activated");
refetchLogRotate();
refetch();
toast.success(
`Requests ${isActive ? "deactivated" : "activated"}`,
);
})
.catch((err) => {
toast.error(err.message);
});
}}
>
Activate Log Rotate
</Button>
)}
<Button>{isActive ? "Deactivate" : "Activate"}</Button>
</DialogAction>
{isLogRotateActive && (
<Button
<DialogAction
title={
isLogRotateActive
? "Activate Log Rotate"
: "Deactivate Log Rotate"
}
description={
isLogRotateActive
? "This will make the logs rotate on interval 1 day and maximum size of 100 MB and maximum 6 logs"
: "The log rotation will be disabled"
}
onClick={() => {
deactivateLogRotate()
toggleLogRotate({
enable: !isLogRotateActive,
})
.then(() => {
toast.success("Log rotate deactivated");
toast.success(
`Log rotate ${isLogRotateActive ? "activated" : "deactivated"}`,
);
refetchLogRotate();
})
.catch((err) => {
@ -63,9 +84,13 @@ export const ShowRequests = () => {
});
}}
>
Deactivate Log Rotate
</Button>
)}
<Button variant="secondary">
{isLogRotateActive
? "Activate Log Rotate"
: "Deactivate Log Rotate"}
</Button>
</DialogAction>
</div>
</div>
</CardHeader>
<CardContent>

View File

@ -0,0 +1,45 @@
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogTrigger,
} from "@/components/ui/alert-dialog";
interface Props {
title?: string;
description?: string;
onClick: () => void;
children?: React.ReactNode;
}
export const DialogAction = ({
onClick,
children,
description,
title,
}: Props) => {
return (
<AlertDialog>
<AlertDialogTrigger asChild>{children}</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>
{title ?? "Are you absolutely sure?"}
</AlertDialogTitle>
<AlertDialogDescription>
{description ?? "This action cannot be undone."}
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction onClick={onClick}>Confirm</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
);
};

View File

@ -41,6 +41,7 @@ import {
} from "@/server/utils/traefik/web-server";
import { generateOpenApiDocument } from "@dokploy/trpc-openapi";
import { TRPCError } from "@trpc/server";
import { dump, load } from "js-yaml";
import { scheduleJob, scheduledJobs } from "node-schedule";
import { z } from "zod";
import { appRouter } from "../root";
@ -372,14 +373,71 @@ export const settingsRouter = createTRPCRouter({
const processedLogs = processLogs(rawConfig as string);
return processedLogs || [];
}),
activateLogRotate: adminProcedure.mutation(async () => {
await logRotationManager.activate();
return true;
}),
deactivateLogRotate: adminProcedure.mutation(async () => {
return await logRotationManager.deactivate();
}),
getLogRotateStatus: adminProcedure.query(async () => {
return await logRotationManager.getStatus();
}),
toggleLogRotate: adminProcedure
.input(
z.object({
enable: z.boolean(),
}),
)
.mutation(async ({ input }) => {
if (input.enable) {
await logRotationManager.activate();
} else {
await logRotationManager.deactivate();
}
return true;
}),
haveActivateRequests: adminProcedure.query(async () => {
const config = readMainConfig();
if (!config) return false;
const parsedConfig = load(config) as {
accessLog?: {
filePath: string;
};
};
return !!parsedConfig?.accessLog?.filePath;
}),
toggleRequests: adminProcedure
.input(
z.object({
enable: z.boolean(),
}),
)
.mutation(async ({ input }) => {
const mainConfig = readMainConfig();
if (!mainConfig) return false;
const currentConfig = load(mainConfig) as {
accessLog?: {
filePath: string;
};
};
if (input.enable) {
const config = {
accessLog: {
filePath: "/etc/dokploy/traefik/dynamic/access.log",
format: "json",
bufferingSize: 100,
filters: {
retryAttempts: true,
minDuration: "10ms",
},
},
};
currentConfig.accessLog = config.accessLog;
} else {
currentConfig.accessLog = undefined;
}
writeMainConfig(dump(currentConfig));
return true;
}),
});

View File

@ -59,12 +59,6 @@ export const createApplication = async (
if (process.env.NODE_ENV === "development") {
createTraefikConfig(newApplication.appName);
await tx.insert(domains).values({
applicationId: newApplication.applicationId,
host: `${newApplication.appName}.docker.localhost`,
port: process.env.NODE_ENV === "development" ? 3000 : 80,
certificateType: "none",
});
}
return newApplication;

View File

@ -99,7 +99,7 @@ class LogRotationManager {
await this.deactivateStream();
}
await execAsync(
"docker kill -s USR1 $(docker ps -q --filter name=traefik)",
"docker kill -s USR1 $(docker ps -q --filter name=dokploy-traefik)",
);
console.log("USR1 Signal send to Traefik");
} catch (error) {

View File

@ -17,6 +17,9 @@ export function processLogs(logString: string): HourlyData[] {
.map((entry) => {
try {
const log: LogEntry = JSON.parse(entry);
if (log.ServiceName === "dokploy-service-app@file") {
return null;
}
const date = new Date(log.StartUTC);
return `${date.toISOString().slice(0, 13)}:00:00Z`;
} catch (error) {
@ -89,6 +92,10 @@ export function parseRawConfig(
parsedLogs = parsedLogs.slice(startIndex, startIndex + page.pageSize);
}
parsedLogs = parsedLogs.filter(
(log) => log.ServiceName !== "dokploy-service-app@file",
);
return { data: parsedLogs, totalCount };
} catch (error) {
console.error("Error parsing rawConfig:", error);

View File

@ -1,7 +1,7 @@
import fs, { writeFileSync } from "node:fs";
import path from "node:path";
import type { Domain } from "@/server/api/services/domain";
import { DYNAMIC_TRAEFIK_PATH } from "@/server/constants";
import { DYNAMIC_TRAEFIK_PATH, MAIN_TRAEFIK_PATH } from "@/server/constants";
import { dump, load } from "js-yaml";
import type { FileConfig, HttpLoadBalancerService } from "./file-types";