import { useEffect, useState } from "react"; import { api } from "../api.js"; interface JobCounts { wait: number; active: number; delayed: number; completed: number; failed: number; paused?: number; } interface WorkerInfo { id: string; addr: string; concurrency: number; lastSeenAt: number; } interface SchedulerInfo { id: string; pattern?: string; every?: number; } interface HealthResponse { ok: boolean; queues: { jobs: JobCounts; deadLetter: JobCounts; }; workers: WorkerInfo[]; schedulers: SchedulerInfo[]; } interface DlqJob { id: string; name: string; data: unknown; failedReason?: string; attemptsMade: number; timestamp: number; } export function WorkersPage() { const [health, setHealth] = useState(null); const [dlq, setDlq] = useState([]); const [error, setError] = useState(null); const [loading, setLoading] = useState(false); const [actionId, setActionId] = useState(null); const load = async () => { setLoading(true); try { const [h, d] = await Promise.all([ api("/admin/v1/workers/health"), api<{ jobs: DlqJob[] }>("/admin/v1/workers/dead-letter?limit=50"), ]); setHealth(h); setDlq(d.jobs); setError(null); } catch (e) { setError(String((e as Error).message)); } finally { setLoading(false); } }; useEffect(() => { load(); const t = setInterval(load, 10_000); return () => clearInterval(t); }, []); const retry = async (id: string) => { setActionId(id); try { await api(`/admin/v1/workers/dead-letter/${id}/retry`, { method: "POST" }); await load(); } catch (e) { setError(String((e as Error).message)); } finally { setActionId(null); } }; const discard = async (id: string) => { if (!confirm("Ta bort jobbet permanent?")) return; setActionId(id); try { await api(`/admin/v1/workers/dead-letter/${id}/discard`, { method: "POST" }); await load(); } catch (e) { setError(String((e as Error).message)); } finally { setActionId(null); } }; return (

Workers & köer

{error &&
{error}
} {loading && !health &&
Laddar …
} {health && ( <>

Jobbkö

Dead letter ({health.queues.deadLetter.wait + health.queues.deadLetter.failed})

{dlq.length === 0 ? (

Inga jobb i dead letter.

) : ( {dlq.map((job) => ( ))}
Jobb Fel Försök Tid Åtgärder
{job.name} {job.failedReason ?? "–"} {job.attemptsMade} {new Date(job.timestamp).toLocaleString("sv-SE")} {" "}
)}

Aktiva worker-instanser

{health.workers.length === 0 ? (

Inga aktiva workers!

) : (
    {health.workers.map((w) => (
  • {w.id} @ {w.addr} (concurrency {w.concurrency})
  • ))}
)}

Scheduler

    {health.schedulers.map((s) => (
  • {s.id}: {s.pattern ?? `every ${s.every}ms`}
  • ))}
)}
); } function Metric({ label, value }: { label: string; value: number }) { return (
{value}
{label}
); }