perf: quick wins for pipeline, jobs, httpapi and web ops
- CDN snapshot: batch merge после parallel fetch, без race на persist - ListRevisionPrefixes: лёгкая проверка revision вместо GetRevision - Jobs: timeout/cancel context для pipeline и deploy - HTTP server timeouts; кэш birdc для GET /peers - ListModules: batch DoH profiles одним запросом - Web: tab-scoped load на /operations, debounce job search, меньше over-fetch на dashboard Co-authored-by: Cursor <[email protected]>
This commit is contained in:
@@ -185,8 +185,8 @@
|
||||
apiJSON<ModulesResponse>('/v1/modules?limit=200'),
|
||||
apiJSON<PeersResponse>('/v1/peers?limit=200'),
|
||||
apiJSON<SpeakersResponse>('/v1/speakers?limit=200'),
|
||||
apiJSON<RevisionsResponse>('/v1/revisions?limit=200'),
|
||||
apiJSON<JobsResponse>('/v1/jobs?limit=20')
|
||||
apiJSON<RevisionsResponse>('/v1/revisions?limit=10'),
|
||||
apiJSON<JobsResponse>('/v1/jobs?limit=10')
|
||||
]);
|
||||
|
||||
const firstReject = [m, p, s, r, j].find((x) => x.status === 'rejected');
|
||||
|
||||
@@ -128,6 +128,7 @@
|
||||
let jobs = $state<JobRow[]>([]);
|
||||
let jobsLoading = $state(false);
|
||||
let jobSearchQ = $state('');
|
||||
let jobSearchDebounced = $state('');
|
||||
let jobFilterStatus = $state('');
|
||||
let jobFilterKind = $state('');
|
||||
let jobFilterModule = $state('');
|
||||
@@ -302,13 +303,23 @@
|
||||
return j.kind === 'module_refresh' && mid === jobFilterModule;
|
||||
});
|
||||
}
|
||||
const q = jobSearchQ.trim();
|
||||
const q = jobSearchDebounced.trim();
|
||||
if (q) {
|
||||
list = list.filter((j) => jobMatchesSearch(j, q));
|
||||
}
|
||||
return list;
|
||||
});
|
||||
|
||||
let jobSearchTimer: ReturnType<typeof setTimeout> | undefined;
|
||||
$effect(() => {
|
||||
const q = jobSearchQ;
|
||||
clearTimeout(jobSearchTimer);
|
||||
jobSearchTimer = setTimeout(() => {
|
||||
jobSearchDebounced = q;
|
||||
}, 250);
|
||||
return () => clearTimeout(jobSearchTimer);
|
||||
});
|
||||
|
||||
const jobModuleOptions = $derived(
|
||||
[...moduleNameById.entries()]
|
||||
.map(([id, name]) => ({ id, name }))
|
||||
@@ -340,8 +351,18 @@
|
||||
|
||||
onMount(() => {
|
||||
activeTab = parseOpsTab(page.url.searchParams.get('tab'));
|
||||
lastLoadedTab = activeTab;
|
||||
tabSyncReady = true;
|
||||
void refreshAll(true);
|
||||
void refreshActiveTab(true);
|
||||
});
|
||||
|
||||
let lastLoadedTab = $state('');
|
||||
$effect(() => {
|
||||
if (!tabSyncReady) return;
|
||||
const tab = activeTab;
|
||||
if (tab === lastLoadedTab) return;
|
||||
lastLoadedTab = tab;
|
||||
void refreshActiveTab();
|
||||
});
|
||||
|
||||
const statAccents = [
|
||||
@@ -425,6 +446,29 @@
|
||||
syncTabToUrl(activeTab);
|
||||
});
|
||||
|
||||
async function refreshActiveTab(isInitial = false) {
|
||||
if (isInitial) initialLoading = true;
|
||||
else refreshing = true;
|
||||
switch (activeTab) {
|
||||
case 'revisions':
|
||||
await loadRevisions();
|
||||
break;
|
||||
case 'jobs':
|
||||
await Promise.all([loadJobs(), loadModules()]);
|
||||
break;
|
||||
case 'diff':
|
||||
break;
|
||||
case 'system':
|
||||
await loadBirdStatus();
|
||||
break;
|
||||
default:
|
||||
await loadRevisions();
|
||||
}
|
||||
lastUpdated = new Date();
|
||||
initialLoading = false;
|
||||
refreshing = false;
|
||||
}
|
||||
|
||||
async function refreshAll(isInitial = false) {
|
||||
if (isInitial) initialLoading = true;
|
||||
else refreshing = true;
|
||||
|
||||
Reference in New Issue
Block a user