admin: live ring capacity is injectable, eviction test no longer timing-bound
Gates / test-aarch64 (push) Failing after 3h1m47s
Gates / package (push) Successful in 4m17s
Gates / container (push) Successful in 15s
CI / gates (push) Failing after 4h45m14s
Gates / frontend (push) Successful in 1m21s
Gates / test (push) Successful in 1m42s

This commit is contained in:
2026-08-23 09:04:18 +02:00
parent 409384ee9e
commit c5875af8c8
3 changed files with 82 additions and 19 deletions
+18 -8
View File
@@ -24,6 +24,12 @@ export interface LiveQueriesOptions {
fetchSince?: (since: number) => Promise<QueriesPage>;
/** Cheap session-gated GET fired once on entering capped, to distinguish an expired session from a real cap. */
probeSession?: () => Promise<unknown>;
/**
* Ring size. Injectable so a test can provoke an eviction with a handful of
* rows instead of pushing 500 frames through React state; the app never
* passes it, and the operator never sees it.
*/
capacity?: number;
}
// A transient drop is invisible to EventSource beyond a bare `error` event;
@@ -34,7 +40,10 @@ export interface LiveQueriesOptions {
export const CAP_ERROR_THRESHOLD = 3;
const defaultEventSource: EventSourceFactory = (url) => new EventSource(url);
const defaultFetchSince = (since: number): Promise<QueriesPage> => api.getQueries({ since, limit: RING_CAPACITY });
const defaultFetchSince =
(capacity: number) =>
(since: number): Promise<QueriesPage> =>
api.getQueries({ since, limit: capacity });
const defaultProbeSession = (): Promise<unknown> => api.getPause();
function isUnauthorized(error: unknown): boolean {
@@ -79,7 +88,8 @@ export function useLiveQueries(options?: LiveQueriesOptions): LiveQueries {
errorsRef.current = 0;
setStatus("connecting");
const opts = optionsRef.current;
const fetchSince = opts?.fetchSince ?? defaultFetchSince;
const capacity = opts?.capacity ?? RING_CAPACITY;
const fetchSince = opts?.fetchSince ?? defaultFetchSince(capacity);
const probeSession = opts?.probeSession ?? defaultProbeSession;
const es = (opts?.createEventSource ?? defaultEventSource)(opts?.url ?? api.liveQueriesUrl);
esRef.current = es;
@@ -94,7 +104,7 @@ export function useLiveQueries(options?: LiveQueriesOptions): LiveQueries {
fetchSince(since).then(
(page) => {
if (esRef.current !== es) return;
const merged = mergeGap(bufferRef.current, page.queries, () => ++keyRef.current);
const merged = mergeGap(bufferRef.current, page.queries, () => ++keyRef.current, capacity);
bufferRef.current = merged.rows;
setRows(merged.rows);
setMissed(merged.missed);
@@ -122,11 +132,11 @@ export function useLiveQueries(options?: LiveQueriesOptions): LiveQueries {
return;
}
lastSeenTsRef.current = payload.request.time;
bufferRef.current = pushRow(bufferRef.current, {
kind: "streamed",
event: payload,
key: ++keyRef.current,
});
bufferRef.current = pushRow(
bufferRef.current,
{ kind: "streamed", event: payload, key: ++keyRef.current },
capacity,
);
setRows(bufferRef.current);
});