fix: address CodeRabbit review for per-site probe

- Fix SSE abort: propagate AbortSignal to worker pool; close connection
  immediately on client disconnect without sending 'complete' event
- Fix Boolean coercion: use strict === true/=== 1 check instead of Boolean()
  to avoid Boolean('false') === true foot-gun
- Fix probe-now: parse and forward latencyThresholdMs from request body
- Fix api.ts probeSiteNow: add latencyThresholdMs to options type
- Fix backup import: restore postRefreshProbe* fields when inserting sites
  so that backup/restore round-trips preserve per-site probe config
- Fix latency threshold persistence: add postRefreshProbeLatencyThresholdMs
  column (migration 0026), save/load it in site editor, pass to
  runPostRefreshProbeIfEnabled so auto-probe also respects the threshold
- Fix state management: setProbeCompleted(false) at probe start; error
  branch also refreshes model lists and sets probeCompleted to show results
- Regenerate schema artifacts (mysql/postgres bootstrap+upgrade, contract)
This commit is contained in:
Xiang Li
2026-04-23 23:08:50 +08:00
parent 37924751f6
commit cb5078468c
13 changed files with 68 additions and 17 deletions
+13 -1
View File
@@ -492,6 +492,7 @@ export default function Sites() {
setProbeEnabled(!!site.postRefreshProbeEnabled);
setProbeModel(typeof site.postRefreshProbeModel === 'string' ? site.postRefreshProbeModel : '');
setProbeScope(site.postRefreshProbeScope === 'all' ? 'all' : 'single');
setProbeLatencyThreshold(String((site as any).postRefreshProbeLatencyThresholdMs ?? 0));
setProbeLog([]);
setProbeCompleted(false);
probeAbortRef.current?.abort();
@@ -563,9 +564,10 @@ export default function Sites() {
postRefreshProbeEnabled: probeEnabled,
postRefreshProbeModel: probeModel.trim(),
postRefreshProbeScope: probeScope,
postRefreshProbeLatencyThresholdMs: Math.max(0, parseInt(probeLatencyThreshold, 10) || 0),
});
setSites((prev) => prev.map((s) => s.id === editor.editingSiteId
? { ...s, postRefreshProbeEnabled: probeEnabled, postRefreshProbeModel: probeModel.trim(), postRefreshProbeScope: probeScope }
? { ...s, postRefreshProbeEnabled: probeEnabled, postRefreshProbeModel: probeModel.trim(), postRefreshProbeScope: probeScope, postRefreshProbeLatencyThresholdMs: Math.max(0, parseInt(probeLatencyThreshold, 10) || 0) }
: s,
));
toast.success('刷新后探测设置已保存');
@@ -588,6 +590,7 @@ export default function Sites() {
probeAbortRef.current = controller;
setProbing(true);
setProbeLog([]);
setProbeCompleted(false);
try {
const token = getAuthToken(localStorage);
@@ -666,6 +669,15 @@ export default function Sites() {
} else if (type === 'error') {
addLog(d.message || '探测失败', 'var(--color-error, #ef4444)');
toast.error(d.message || '探测失败');
// Refresh model state even on error
Promise.all([
api.getSiteAvailableModels(siteId).then((res: any) => {
setAvailableModels(Array.isArray(res?.models) ? res.models : []);
}),
api.getSiteDisabledModels(siteId).then((res: any) => {
setDisabledModels(Array.isArray(res?.models) ? res.models : []);
}),
]).catch(() => {}).finally(() => setProbeCompleted(true));
}
} catch { /* ignore parse errors */ }
};