fix(runtime): bound Runs readback polling
Some checks failed
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Failing after 47s
CD Pipeline / build-and-deploy (push) Has been skipped
CD Pipeline / post-deploy-checks (push) Has been skipped

This commit is contained in:
ogt
2026-07-15 02:30:30 +08:00
parent 99499bd533
commit 0f681ca277
8 changed files with 229 additions and 78 deletions

View File

@@ -1,6 +1,6 @@
"use client";
import { useCallback, useEffect, useMemo, useState } from "react";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useLocale, useTranslations } from "next-intl";
import {
Activity,
@@ -467,6 +467,7 @@ type AutomationWorkItem = {
};
const API_BASE = getRuntimeApiBaseUrl();
const AUTO_REFRESH_INTERVAL = 90_000;
function numberValue(value: unknown): string {
const numeric = Number(value ?? 0);
@@ -644,39 +645,55 @@ export function AutonomousRuntimeReceiptPanel({
const [error, setError] = useState(false);
const [updatedAt, setUpdatedAt] = useState<Date | null>(null);
const [workFilter, setWorkFilter] = useState<WorkFilter>("all");
const refreshInFlightRef = useRef(false);
const refresh = useCallback(async () => {
if (refreshInFlightRef.current) return;
refreshInFlightRef.current = true;
setLoading(true);
const next = await fetchRuntimeControl();
setPayload(next);
setError(next === null);
setUpdatedAt(next ? new Date() : null);
setLoading(false);
try {
const next = await fetchRuntimeControl();
if (next) {
setPayload(next);
setUpdatedAt(new Date());
}
setError(next === null);
const [
priority,
consumer,
telegramVerifier,
telegramCoverage,
telegramLiveReceiptApply,
] = await Promise.all([
fetchPriorityWorkOrder(),
fetchLogConsumerReadback(),
fetchTelegramPostApplyVerifier(),
fetchTelegramMonitoringCoverage(),
fetchTelegramMonitoringLiveReceiptApplyReadback(),
]);
setPriorityPayload(priority);
setConsumerPayload(consumer);
setTelegramVerifierPayload(telegramVerifier);
setTelegramCoveragePayload(telegramCoverage);
setTelegramLiveReceiptApplyPayload(telegramLiveReceiptApply);
// These endpoints share the same bounded DB pool. Keep them serialized so
// one browser cannot starve health probes or create overlapping readbacks.
const priority = await fetchPriorityWorkOrder();
if (priority) setPriorityPayload(priority);
const consumer = await fetchLogConsumerReadback();
if (consumer) setConsumerPayload(consumer);
const telegramVerifier = await fetchTelegramPostApplyVerifier();
if (telegramVerifier) setTelegramVerifierPayload(telegramVerifier);
const telegramCoverage = await fetchTelegramMonitoringCoverage();
if (telegramCoverage) setTelegramCoveragePayload(telegramCoverage);
const telegramLiveReceiptApply =
await fetchTelegramMonitoringLiveReceiptApplyReadback();
if (telegramLiveReceiptApply) {
setTelegramLiveReceiptApplyPayload(telegramLiveReceiptApply);
}
} finally {
setLoading(false);
refreshInFlightRef.current = false;
}
}, []);
useEffect(() => {
refresh();
const timer = window.setInterval(refresh, 30_000);
return () => window.clearInterval(timer);
let cancelled = false;
let timer: number | null = null;
const poll = async () => {
await refresh();
if (!cancelled) {
timer = window.setTimeout(() => void poll(), AUTO_REFRESH_INTERVAL);
}
};
void poll();
return () => {
cancelled = true;
if (timer !== null) window.clearTimeout(timer);
};
}, [refresh]);
const hasRuntimeReadback = payload !== null;
@@ -1605,7 +1622,7 @@ export function AutonomousRuntimeReceiptPanel({
</span>
<button
type="button"
onClick={refresh}
onClick={() => void refresh()}
disabled={loading}
className="inline-flex items-center gap-2 border border-[#d8d3c7] bg-white px-3 py-2 text-xs font-semibold text-[#141413] hover:border-[#d97757] disabled:opacity-60"
aria-label={t("refresh")}