diff --git a/src/components/wrappers/dashboard/health/heath-grid.tsx b/src/components/wrappers/dashboard/health/heath-grid.tsx index e6781a7d..50f9e157 100644 --- a/src/components/wrappers/dashboard/health/heath-grid.tsx +++ b/src/components/wrappers/dashboard/health/heath-grid.tsx @@ -3,6 +3,7 @@ import {useMemo} from "react" import {Card} from "@/components/ui/card" import {HealthcheckLog} from "@/db/schema/15_healthcheck-log" +import {useIsMobile} from "@/hooks/use-mobile"; type HealthStatus = "healthy" | "degraded" | "down" | "unknown" @@ -105,11 +106,12 @@ export const HealthCheckGraph = ({logs}: Props) => { return buildTimeSeries(logs) }, [logs]) + const isMobile = useIsMobile() + const hourLabels = useMemo(() => { if (data.length === 0) return [] - const isMobile = window.innerWidth <= 768 return data .map((item, index) => ({ item, index })) diff --git a/src/db/services/healthcheck.ts b/src/db/services/healthcheck.ts new file mode 100644 index 00000000..5632c27c --- /dev/null +++ b/src/db/services/healthcheck.ts @@ -0,0 +1,41 @@ +import {db} from "@/db"; +import * as drizzleDb from "@/db"; +import {and, eq, gte, lt} from "drizzle-orm"; + +export async function getHealthLast12hLogs({id}: { id: string }) { + const now = new Date() + const since = new Date(now.getTime() - 12 * 60 * 60 * 1000) + + return db + .select() + .from(drizzleDb.schemas.healthcheckLog) + .where( + and( + eq(drizzleDb.schemas.healthcheckLog.objectId, id), + gte(drizzleDb.schemas.healthcheckLog.date, since) + ) + ) +} + + +export async function deleteHealthLogsOlderThan12h() { + const now = new Date() + const threshold = new Date(now.getTime() - 12 * 60 * 60 * 1000) + + const logsToDelete = await db + .select() + .from(drizzleDb.schemas.healthcheckLog) + .where( + lt(drizzleDb.schemas.healthcheckLog.date, threshold) + ) + + console.log(`Number of logs found to delete: ${logsToDelete.length}`) + + await db + .delete(drizzleDb.schemas.healthcheckLog) + .where( + lt(drizzleDb.schemas.healthcheckLog.date, threshold) + ) + + return logsToDelete.length +} \ No newline at end of file diff --git a/src/env.mjs b/src/env.mjs index bef0349d..8e10c823 100644 --- a/src/env.mjs +++ b/src/env.mjs @@ -39,6 +39,14 @@ export const env = createEnv({ process.env.NODE_ENV === "production" ? "0 7 * * *" : "* * * * *", ), + CLEANING_HEALTHCHECK_LOGS_CRON: z + .string() + .default( + process.env.NODE_ENV === "production" ? "0 * * * *" : "* * * * *", + ), + + + AUTH_OIDC_ID: z.string().optional().default("oidc"), AUTH_OIDC_TITLE: z.string().optional(), AUTH_OIDC_DESC: z.string().optional(), @@ -95,6 +103,7 @@ export const env = createEnv({ SMTP_SECURE: process.env.SMTP_SECURE, RETENTION_CRON: process.env.RETENTION_CRON, + CLEANING_HEALTHCHECK_LOGS_CRON: process.env.CLEANING_HEALTHCHECK_LOGS_CRON, AUTH_OIDC_ID: process.env.AUTH_OIDC_ID, AUTH_OIDC_TITLE: process.env.AUTH_OIDC_TITLE, diff --git a/src/features/agents/agents.action.ts b/src/features/agents/agents.action.ts index 6a6f0a21..ee48b0e2 100644 --- a/src/features/agents/agents.action.ts +++ b/src/features/agents/agents.action.ts @@ -2,10 +2,11 @@ import {ActionError, userAction} from "@/lib/safe-actions/actions"; import {AgentSchema} from "@/features/agents/agents.schema"; import {z} from "zod"; -import {eq, and, ne, count, gte} from "drizzle-orm"; +import {eq, and, ne, count, gte, lt} from "drizzle-orm"; import {db} from "@/db"; import * as drizzleDb from "@/db"; import {slugify} from "@/utils/slugify"; +import {getHealthLast12hLogs} from "@/db/services/healthcheck"; const verifySlugUniqueness = async (slug: string, agentId?: string) => { const conditions = agentId ? and(eq(drizzleDb.schemas.agent.slug, slug), ne(drizzleDb.schemas.agent.id, agentId)) : eq(drizzleDb.schemas.agent.slug, slug); @@ -57,22 +58,7 @@ export const getAgentAction = userAction.schema(z.string()).action(async ({parse return { data: agent, - health: agent ? await getLast12hLogs({ id: agent.id }) : [] + health: agent ? await getHealthLast12hLogs({ id: agent.id }) : [] }; }); - -export async function getLast12hLogs({id}: { id: string }) { - const now = new Date() - const since = new Date(now.getTime() - 12 * 60 * 60 * 1000) - - return db - .select() - .from(drizzleDb.schemas.healthcheckLog) - .where( - and( - eq(drizzleDb.schemas.healthcheckLog.objectId, id), - gte(drizzleDb.schemas.healthcheckLog.date, since) - ) - ) -} diff --git a/src/lib/tasks/index.ts b/src/lib/tasks/index.ts index 430bbaae..dc4de157 100644 --- a/src/lib/tasks/index.ts +++ b/src/lib/tasks/index.ts @@ -2,7 +2,7 @@ import cron from "node-cron"; import {retentionCleanTask} from "@/lib/tasks/database"; import {env} from "@/env.mjs"; import {backupCleanTask} from "@/lib/tasks/cleaning"; - +import {deleteHealthLogsOlderThan12h} from "@/db/services/healthcheck"; export const retentionJob = cron.schedule(env.RETENTION_CRON, async () => { try { @@ -20,4 +20,13 @@ export const cleaningJob = cron.schedule("* * * * *", async () => { } catch (err) { console.error(`[CRON] Error:`, err); } +}); + +export const cleaningHealthcheckLogsJob = cron.schedule(env.CLEANING_HEALTHCHECK_LOGS_CRON, async () => { + try { + console.log("Cleaning Healthcheck Logs Job : Starting task"); + await deleteHealthLogsOlderThan12h(); + } catch (err) { + console.error(`[CRON] Error:`, err); + } }); \ No newline at end of file diff --git a/src/utils/init.ts b/src/utils/init.ts index ee274813..2ad28f22 100644 --- a/src/utils/init.ts +++ b/src/utils/init.ts @@ -2,7 +2,7 @@ import { env } from "@/env.mjs"; import { db, makeMigration } from "@/db"; import { eq } from "drizzle-orm"; import * as drizzleDb from "@/db"; -import { cleaningJob, retentionJob } from "@/lib/tasks"; +import {cleaningHealthcheckLogsJob, cleaningJob, retentionJob} from "@/lib/tasks"; import { generateRSAKeys, getOrCreateMasterKey } from "@/utils/rsa-keys"; import { StorageProviderKind } from "@/features/storages/types"; @@ -17,6 +17,7 @@ export async function init() { console.log("====Initialization completed===="); await setupCronJobs(); await setupCleaningJobs(); + await setupCleaningHealthLogsJobs(); if ( (env.AUTH_GOOGLE_ID && env.AUTH_GOOGLE_SECRET) || @@ -40,6 +41,12 @@ async function setupCleaningJobs() { console.log("==== Cleaning job started ===="); } +async function setupCleaningHealthLogsJobs() { + console.log("==== Setting up Cleaning Healthcheck Logs Jobs ===="); + cleaningHealthcheckLogsJob.start(); + console.log("==== Cleaning Healthcheck Logs job started ===="); +} + async function createSettingsIfNotExist() { await db.transaction(async (tx) => { const systemSettingsValues = {