5d0a61c38e
User-Entscheid 15.07. abends: P3-Worker-Jobs abgebrochen (22 Anlaeufe, 0 Ergebnisse) - 'du bearbeitest sie ein letztes Mal manuell'. P3a KOMPLETT: backend/routers/events.py streamt SSE; ein Sammler prueft alle 3 s billige Fingerabdruecke (Briefkasten-Cursor, Queue-Status, Auftragsbuch-/Reminder-mtimes) und schickt bei Aenderung 'invalidate' mit den React-Query-Keys. frontend/src/lib/events.ts haelt EIN EventSource, invalidiert gezielt und entspannt die vier gedeckten Poller x5 (relax() in queries.ts); reisst der Strom, reconnectet EventSource selbst und die UI pollt wie bisher. Live-Graphen bleiben bewusst beim Polling (aendern sich jede Sekunde). P3b (TanStack Router) BEWUSST NICHT umgesetzt: Hash-Navigation liefert Deep-Links + Zuruecktaste bereits; Router-Migration = hohes Regressions- risiko ueber alle Views bei minimalem Gewinn fuer 1-Nutzer-LAN (gleiche Logik wie das React-bleibt-Verdikt in UMBAUPLAN 3b). P3c (OpenAPI-Typen) VERTAGT: ohne Pydantic-response_models liefert der Generator leere Typen - Voraussetzung ist erst das Backend-Typing (eigene, klein geschnittene Karten-Serie). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
28 lines
1.1 KiB
TypeScript
28 lines
1.1 KiB
TypeScript
// SSE-Eventstrom (UMBAU v3 P3a) — Gegenstück zu backend/routers/events.py.
|
||
// EIN EventSource auf /api/events; `invalidate`-Events stoßen gezielt die React-Query-
|
||
// Caches an. Solange der Strom steht, sind die Poller nur noch Sicherheitsnetz
|
||
// (queries.ts entspannt sie ×5 über sseVerbunden()). Reißt der Strom (MC2-Deploy,
|
||
// Netz), reconnectet EventSource von selbst — bis dahin pollt die UI wie früher.
|
||
|
||
import { useEffect } from "react"
|
||
import { useQueryClient } from "@tanstack/react-query"
|
||
|
||
let verbunden = false
|
||
export const sseVerbunden = () => verbunden
|
||
|
||
export function useEventStream() {
|
||
const qc = useQueryClient()
|
||
useEffect(() => {
|
||
const es = new EventSource("/api/events")
|
||
es.onopen = () => { verbunden = true }
|
||
es.onerror = () => { verbunden = false }
|
||
es.addEventListener("invalidate", (e) => {
|
||
try {
|
||
const keys: string[] = JSON.parse((e as MessageEvent).data)?.keys ?? []
|
||
for (const k of keys) qc.invalidateQueries({ queryKey: [k] })
|
||
} catch { /* kaputtes Event bricht den Strom nicht */ }
|
||
})
|
||
return () => { verbunden = false; es.close() }
|
||
}, [qc])
|
||
}
|