98 lines
2.9 KiB
TypeScript
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.",
|
|
}
|
|
}
|