sistema-de-chamados/src/server/health.ts
2025-12-10 14:43:13 -03:00

98 lines
2.9 KiB
TypeScript

import { api } from "@/convex/_generated/api"
import { RETENTION_POLICY, RETENTION_STRATEGY } from "@/lib/retention"
import { prisma } from "@/lib/prisma"
import { createConvexClient } from "@/server/convex-client"
import { env } from "@/lib/env"
const OPEN_TICKET_STATUSES = ["PENDING", "AWAITING_ATTENDANCE", "PAUSED"]
type DeviceHealth = {
machines: number
online: number
warning: number
offline: number
withoutHeartbeat: number
newestHeartbeatAgeMs: number | null
oldestHeartbeatAgeMs: number | null
thresholds: {
offlineMs: number
staleMs: number
}
truncated: boolean
}
export type HealthSnapshot = {
generatedAt: string
tickets: {
total: number
open: number
last7d: number
last24h: number
}
accounts: {
users: number
companies: number
}
devices: DeviceHealth | null
retention: typeof RETENTION_POLICY
retentionStrategy: typeof RETENTION_STRATEGY
notes?: string
}
function toIsoString(date: Date) {
return date.toISOString()
}
export async function getHealthSnapshot(): Promise<HealthSnapshot> {
const now = new Date()
const sevenDaysAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000)
const oneDayAgo = new Date(now.getTime() - 24 * 60 * 60 * 1000)
const [totalTickets, openTickets, lastWeekTickets, lastDayTickets, userCount, companyCount] = await Promise.all([
prisma.ticket.count(),
prisma.ticket.count({ where: { status: { in: OPEN_TICKET_STATUSES } } }),
prisma.ticket.count({ where: { createdAt: { gte: sevenDaysAgo } } }),
prisma.ticket.count({ where: { createdAt: { gte: oneDayAgo } } }),
prisma.user.count(),
prisma.company.count(),
])
let devices: DeviceHealth | null = null
try {
const client = createConvexClient()
const convexHealth = await client.query(api.ops.healthSnapshot, {
token: env.INTERNAL_HEALTH_TOKEN ?? env.REPORTS_CRON_SECRET ?? undefined,
})
devices = {
machines: convexHealth.totals.machines,
online: convexHealth.connectivity.online,
warning: convexHealth.connectivity.warning,
offline: convexHealth.connectivity.offline,
withoutHeartbeat: convexHealth.totals.withoutHeartbeat,
newestHeartbeatAgeMs: convexHealth.heartbeatAgeMs.newest,
oldestHeartbeatAgeMs: convexHealth.heartbeatAgeMs.oldest,
thresholds: convexHealth.thresholds,
truncated: convexHealth.totals.truncated,
}
} catch (error) {
console.error("[health] Falha ao carregar estado das maquinas", error)
}
return {
generatedAt: toIsoString(now),
tickets: {
total: totalTickets,
open: openTickets,
last7d: lastWeekTickets,
last24h: lastDayTickets,
},
accounts: {
users: userCount,
companies: companyCount,
},
devices,
retention: RETENTION_POLICY,
retentionStrategy: RETENTION_STRATEGY,
notes: devices ? undefined : "Convex nao respondeu; verificar conectividade ou token interno.",
}
}