mirror of
https://github.com/lukaszraczylo/traefik-llmgateway.git
synced 2026-10-15 05:29:28 +00:00
feat(admin): show target health in the dashboard
Add a Health column to the MCP servers and A2A agents tables in TargetsView. An unhealthy target renders a destructive badge with the age of its last check and carries the failure count, source, and scrubbed last error in the title. An unknown target renders an outline badge and, when it has failed but never succeeded, the same failure details in its title. A healthy target renders muted text with its last observed latency and no badge, matching the providers' convention. Add AdminTargetHealthView to the API types with the wire contract the Go side emits, a bare formatElapsedAgo helper next to formatAgo, and column-cell tests for all three states. Regenerate the baked admin assets. Claude-Session: https://claude.ai/code/session_01EebV5jyWvYocByNQ3oss1w
This commit is contained in:
@@ -316,6 +316,43 @@ export interface AdminTargetCountersView {
|
||||
requestsPerMonth: number
|
||||
}
|
||||
|
||||
/**
|
||||
* One configured MCP server's or A2A agent's current health, matching the
|
||||
* GET /admin/api/targets `health` object the Go side builds against
|
||||
* (feat/target-health). Two independent sources feed `state`, never
|
||||
* conflated: 'traffic' is PASSIVE — recorded from the target's own real
|
||||
* proxied/federated request traffic as it happens, no extra requests
|
||||
* sent; 'probe' is the gateway's own lazy health check, triggered
|
||||
* opportunistically by an operator hitting /metrics, /admin, or a listing
|
||||
* endpoint (never a background poller). `state` is 'unhealthy' once at
|
||||
* least the configured `failureThreshold` consecutive failures have been
|
||||
* observed (whether or not this target has ever succeeded), 'healthy'
|
||||
* once it has succeeded at least once and stays below that threshold, and
|
||||
* 'unknown' otherwise. `consecutiveFailures` is always present.
|
||||
*
|
||||
* 'unknown' reads two different ways server-side, and only ONE of them
|
||||
* omits the rest of this object (F4, feat/target-health review):
|
||||
* - never observed by either source at all: every other field is
|
||||
* omitted — there is truly nothing to report.
|
||||
* - observed, but never once succeeded, still below `failureThreshold`:
|
||||
* every other field is PRESENT — `lastCheck`/`lastError`/`latencyMs`/
|
||||
* `source` all carry a real observation, this target simply has not
|
||||
* answered successfully yet. Do not treat 'unknown' as "no data" for
|
||||
* this case; check whether `lastCheck` is set instead.
|
||||
*
|
||||
* `lastError` is additionally omitted whenever it is empty (a healthy
|
||||
* target has nothing to show), and `latencyMs`/`source` are omitted only
|
||||
* when genuinely not known (the never-observed case above).
|
||||
*/
|
||||
export interface AdminTargetHealthView {
|
||||
state: 'healthy' | 'unhealthy' | 'unknown'
|
||||
lastCheck?: string
|
||||
lastError?: string
|
||||
consecutiveFailures: number
|
||||
latencyMs?: number
|
||||
source?: 'probe' | 'traffic'
|
||||
}
|
||||
|
||||
/**
|
||||
* One configured MCP server's or A2A agent's row in GET /admin/api/targets
|
||||
* (admin.go: adminTargetView). Access is the group names actually allowed
|
||||
@@ -329,6 +366,8 @@ export interface AdminTargetView {
|
||||
url: string
|
||||
access?: string[]
|
||||
counters: AdminTargetCountersView
|
||||
/** See AdminTargetHealthView's own doc comment (feat/target-health) — always present, unlike access above. */
|
||||
health: AdminTargetHealthView
|
||||
}
|
||||
|
||||
/** GET /admin/api/targets (admin.go: adminTargetsResponse). */
|
||||
|
||||
Reference in New Issue
Block a user