SysDeck/klanker-gate/apps/gateway/routes/runtime.ts

159 lines
5.3 KiB
TypeScript
Executable File

import type { AppContext } from "../context.ts";
import type { Router } from "../../../packages/core/src/mod.ts";
import { jsonResponse } from "./helpers.ts";
import { planCluster, reusePortSupported } from "../cluster.ts";
import { poolSizeFromEnv } from "../../../packages/config/src/pg.ts";
import type { ConcurrencySnapshot } from "../../../packages/telemetry/src/concurrency.ts";
export interface WorkerTopology {
/** FROSTY_WORKERS as configured. 1 means single-process. */
configured: number;
/** Processes actually serving. Equals `configured` only where reusePort works. */
effective: number;
/** This process's index, or null in single-process mode. */
index: number | null;
/** Whether this platform can share a port across processes. */
reusePortSupported: boolean;
platform: string;
/** Why the effective count is what it is - surfaced verbatim in the UI. */
reason: string;
}
export interface RateLimitState {
/** Whether any virtual key carries a rate-limit policy. */
enforced: boolean;
/** Virtual keys that declare a rate limit. */
keysWithLimits: number;
/** Total virtual keys, for the "N of M" reading. */
totalKeys: number;
/**
* `fleet` when a shared authority enforces the windows (decision-log 71) -
* one budget however many workers serve. `per-process` is the fallback when
* no shared store is attached, where N workers admit up to N times the
* stated value. Budgets are always fleet-wide (shared atomic counters).
*/
scope: "fleet" | "per-process";
windows: Array<{ keyId: string; maxRequests?: number; windowMs: number }>;
}
export interface RuntimeView {
workers: WorkerTopology;
concurrency: ConcurrencySnapshot & { scope: "per-process" };
rateLimit: RateLimitState;
postgres: {
/** Connections this process may hold. */
poolSize: number;
/** poolSize x effective workers, plus one LISTEN connection per worker. */
estimatedFleetConnections: number;
/** host:port/database - never credentials. */
target: string;
/** Whether the cross-process invalidation listener is registered. */
listenerActive: boolean;
};
cache: {
/** exact | semantic | off. */
mode: string;
/** Whether a shared L2 tier is attached. */
sharedTier: boolean;
/** Entries in THIS process's L1. */
localEntries: number;
};
process: {
uptimeSeconds: number;
denoVersion: string;
v8Version: string;
};
}
/** Strips credentials from a connection URL, keeping host:port/database. */
export function redactPgTarget(raw: string | undefined): string {
if (!raw) {
return "not configured";
}
try {
const url = new URL(raw);
const database = url.pathname.replace(/^\//, "") || "(default)";
return `${url.host}/${database}`;
} catch {
// An unparseable URL must not be echoed back - it could be a
// paste-accident containing a password in an unexpected shape.
return "(unparseable)";
}
}
const BOOT_MS = Date.now();
export function registerRuntimeRoutes(router: Router, ctx: AppContext): void {
router.get("/api/runtime", () => {
const plan = planCluster();
const configured = Number(Deno.env.get("FROSTY_WORKERS") ?? "1");
const validConfigured = Number.isInteger(configured) && configured > 0
? configured
: 1;
const effective = reusePortSupported() ? validConfigured : 1;
const rawIndex = Number(Deno.env.get("FROSTY_WORKER_INDEX") ?? "");
const poolSize = poolSizeFromEnv();
const keys = ctx.virtualKeys.list();
const windows = keys
.filter((key) => key.rateLimit !== undefined)
.map((key) => ({
keyId: key.id,
maxRequests: key.rateLimit?.maxRequests,
windowMs: key.rateLimit?.windowMs ?? 0,
}));
const view: RuntimeView = {
workers: {
configured: validConfigured,
effective,
index: Number.isInteger(rawIndex) ? rawIndex : null,
reusePortSupported: reusePortSupported(),
platform: Deno.build.os,
reason: plan.reason,
},
concurrency: {
...(ctx.concurrency?.snapshot() ?? {
active: 0,
peak: 0,
total: 0,
completed: 0,
avgLifetimeMs: 0,
maxLifetimeMs: 0,
longestOpenMs: 0,
dispatching: 0,
peakDispatching: 0,
since: new Date(BOOT_MS).toISOString(),
}),
scope: "per-process",
},
rateLimit: {
enforced: windows.length > 0,
keysWithLimits: windows.length,
totalKeys: keys.length,
scope: ctx.sharedRateLimit ? "fleet" : "per-process",
windows,
},
postgres: {
poolSize,
// Each worker holds a pool AND one session connection for LISTEN.
estimatedFleetConnections: effective * poolSize + effective,
target: redactPgTarget(Deno.env.get("FROSTY_PG_URL")),
listenerActive: ctx.invalidation !== undefined,
},
cache: {
mode: Deno.env.get("FROSTY_CACHE") || "off",
sharedTier: Boolean(ctx.cache) &&
Deno.env.get("FROSTY_CACHE") !== undefined,
localEntries: ctx.cache?.size() ?? 0,
},
process: {
uptimeSeconds: Math.floor((Date.now() - BOOT_MS) / 1000),
denoVersion: Deno.version.deno,
v8Version: Deno.version.v8,
},
};
return jsonResponse(view);
});
}