UNPKG

convex

Version:

Client for the Convex Cloud

199 lines (179 loc) 5.52 kB
import { Context } from "../../bundler/context.js"; import { fetchTeamAndProject } from "./api.js"; import { bigBrainFetch, provisionHost } from "./utils/utils.js"; export const ROOT_COMPONENT_PATH = "-root-component-"; // Query ID for the insights dataset (shared with dashboard/src/api/insights.ts). export const INSIGHTS_QUERY_ID = "9ab3b74e-a725-480b-88a6-43e6bd70bd82"; export type OccRecentEvent = { timestamp: string; id: string; request_id: string; occ_document_id?: string; occ_write_source?: string; occ_retry_count: number; }; export type ResourceRecentEvent = { timestamp: string; id: string; request_id: string; calls: { table_name: string; bytes_read: number; documents_read: number; }[]; success: boolean; }; export type OccInsight = { kind: "occRetried" | "occFailedPermanently"; severity: "error" | "warning"; functionId: string; componentPath: string | null; occCalls: number; occTableName?: string | undefined; recentEvents?: OccRecentEvent[] | undefined; }; export type ResourceInsight = { kind: | "bytesReadLimit" | "bytesReadThreshold" | "documentsReadLimit" | "documentsReadThreshold"; severity: "error" | "warning"; functionId: string; componentPath: string | null; count: number; recentEvents?: ResourceRecentEvent[] | undefined; }; export type Insight = OccInsight | ResourceInsight; // Sorted from most to least severe. const insightKinds: { kind: string; severity: "error" | "warning" }[] = [ { kind: "documentsReadLimit", severity: "error" }, { kind: "bytesReadLimit", severity: "error" }, { kind: "occFailedPermanently", severity: "error" }, { kind: "documentsReadThreshold", severity: "warning" }, { kind: "bytesReadThreshold", severity: "warning" }, { kind: "occRetried", severity: "warning" }, ]; const insightKindMap = new Map( insightKinds.map((ik, i) => [ik.kind, { severity: ik.severity, order: i }]), ); export function orderForKind(kind: string): number { return insightKindMap.get(kind)?.order ?? insightKinds.length; } export function severityForKind(kind: string): "error" | "warning" | undefined { return insightKindMap.get(kind)?.severity; } const MAX_RECENT_EVENTS = 5; function parseRow(row: string[], includeRecentEvents: boolean): Insight | null { const kind = row[0]; const functionId = row[1]; const componentPath = row[2] === ROOT_COMPONENT_PATH ? null : row[2]; const details = JSON.parse(row[3]); const common = { functionId, componentPath }; const recentEvents = includeRecentEvents ? (details.recentEvents as any[]).slice(0, MAX_RECENT_EVENTS) : undefined; switch (kind) { case "occRetried": return { kind, severity: "warning" as const, ...common, occCalls: details.occCalls, occTableName: details.occTableName, recentEvents, }; case "occFailedPermanently": return { kind, severity: "error" as const, ...common, occCalls: details.occCalls, occTableName: details.occTableName, recentEvents, }; case "bytesReadLimit": return { kind, severity: "error" as const, ...common, count: details.count, recentEvents, }; case "bytesReadThreshold": return { kind, severity: "warning" as const, ...common, count: details.count, recentEvents, }; case "documentsReadLimit": return { kind, severity: "error" as const, ...common, count: details.count, recentEvents, }; case "documentsReadThreshold": return { kind, severity: "warning" as const, ...common, count: details.count, recentEvents, }; default: return null; } } /** * Fetch raw insight rows from the Big Brain usage API. * Returns the raw string[][] from the API response. */ export async function fetchRawInsightsData( ctx: Context, deploymentName: string, ): Promise<string[][]> { const { teamId } = await fetchTeamAndProject(ctx, deploymentName); const now = new Date(); const hoursAgo72 = new Date(now.getTime() - 72 * 60 * 60 * 1000); const fromDate = hoursAgo72.toISOString().split("T")[0]; const toDate = now.toISOString().split("T")[0]; const queryParams = new URLSearchParams({ queryId: INSIGHTS_QUERY_ID, deploymentName, from: fromDate, to: toDate, }); const bbFetch = await bigBrainFetch(ctx); const res = await bbFetch( `dashboard/teams/${teamId}/usage/query?${queryParams.toString()}`, { method: "GET", headers: { Origin: provisionHost }, }, ); return (await res.json()) as string[][]; } /** * Fetch and parse insights from the Big Brain usage API for a deployment. * Returns insights sorted by severity (errors first). * * Pass `includeRecentEvents: true` to include up to 5 recent events per insight. */ export async function fetchInsights( ctx: Context, deploymentName: string, options?: { includeRecentEvents?: boolean }, ): Promise<Insight[]> { const rawData = await fetchRawInsightsData(ctx, deploymentName); const includeRecentEvents = options?.includeRecentEvents ?? false; const insights: Insight[] = rawData.flatMap((row) => { const parsed = parseRow(row, includeRecentEvents); return parsed ? [parsed] : []; }); insights.sort((a, b) => orderForKind(a.kind) - orderForKind(b.kind)); return insights; }