perf: speed up code queue first paint

This commit is contained in:
Codex
2026-05-16 04:34:25 +00:00
parent 860b2a76b1
commit f1a6cb509b
2 changed files with 107 additions and 32 deletions
+62 -5
View File
@@ -14,7 +14,7 @@ const h = React.createElement;
const { useEffect, useMemo, useRef } = React;
const useState: any = React.useState;
const codexTranscriptChunkLimit = 120;
const codexInitialTaskLimit = 24;
const codexInitialTaskLimit = 12;
const codexMoreTaskLimit = 48;
const queueErrorPreviewLength = 1200;
@@ -317,14 +317,18 @@ function queueRunnableTaskId(queueRows: any[], queueId: string, rows: any[]): st
async function loadTaskList(apiBaseUrl: string, queueId = allQueuesId, searchQuery = ""): Promise<any> {
return requestJson(codexApi(
apiBaseUrl,
`/api/tasks/overview?limit=${codexInitialTaskLimit}&transcriptLimit=1&compact=1&selected=0&skipTrace=1${taskListQuerySuffix(queueId, searchQuery)}`,
`/api/tasks/overview?limit=${codexInitialTaskLimit}&transcriptLimit=1&compact=1&selected=0&includeActive=0&stats=0&skipTrace=1${taskListQuerySuffix(queueId, searchQuery)}`,
), codexNoCacheOptions());
}
async function loadTaskOverview(apiBaseUrl: string, preferId: string, afterSeq = 0, queueId = allQueuesId, searchQuery = "", skipTrace = false): Promise<any> {
async function loadTaskOverview(apiBaseUrl: string, preferId: string, afterSeq = 0, queueId = allQueuesId, searchQuery = "", skipTrace = false, options: AnyRecord = {}): Promise<any> {
const selectedParam = options.selected === false ? "&selected=0" : "";
const includeActiveParam = options.includeActive === false ? "&includeActive=0" : "";
const statsParam = options.stats === false ? "&stats=0" : "";
const limit = Number.isInteger(options.limit) && options.limit > 0 ? Math.min(500, options.limit) : codexInitialTaskLimit;
return requestJson(codexApi(
apiBaseUrl,
`/api/tasks/overview?limit=${codexInitialTaskLimit}&transcriptLimit=3&compact=1&afterSeq=${encodeURIComponent(String(Math.max(0, afterSeq)))}&preferId=${encodeURIComponent(preferId)}${skipTrace ? "&skipTrace=1" : ""}${taskListQuerySuffix(queueId, searchQuery)}`,
`/api/tasks/overview?limit=${encodeURIComponent(String(limit))}&transcriptLimit=3&compact=1&afterSeq=${encodeURIComponent(String(Math.max(0, afterSeq)))}&preferId=${encodeURIComponent(preferId)}${selectedParam}${includeActiveParam}${statsParam}${skipTrace ? "&skipTrace=1" : ""}${taskListQuerySuffix(queueId, searchQuery)}`,
), codexNoCacheOptions());
}
@@ -2528,7 +2532,10 @@ export function CodeQueuePage({ microservices, onRaw, apiBaseUrl = "/api", initi
const requestedTranscript = Array.isArray(requestedCached?.task?.transcript) ? requestedCached.task.transcript : [];
const overviewAfterSeq = transcriptResumeSeq(requestedTranscript);
let tasksResult = null;
tasksResult = await loadTaskOverview(apiBaseUrl, requestedId, overviewAfterSeq, queueFilterId, "", true);
const firstPaintListOnly = trackLoad && requestedId.length === 0;
tasksResult = firstPaintListOnly
? await loadTaskList(apiBaseUrl, queueFilterId, "")
: await loadTaskOverview(apiBaseUrl, requestedId, overviewAfterSeq, queueFilterId, "", true, { stats: false });
if (token !== queueLoadTokenRef.current) {
if (trackLoad) trackedLoadInFlightRef.current = false;
return;
@@ -2574,6 +2581,56 @@ export function CodeQueuePage({ microservices, onRaw, apiBaseUrl = "/api", initi
const cached = sessionCacheRef.current.get(nextId);
if (cached?.task) sessionCacheRef.current.set(nextId, { ...cached, task: { ...row, ...cached.task, status: row.status, updatedAt: row.updatedAt } });
}
if (firstPaintListOnly && row) {
publishCachedTask(nextId, {
...row,
_summaryLoaded: false,
transcript: [],
_detailLoaded: false,
_transcriptComplete: false,
_transcriptPreview: true,
}, detailLoadTokenRef.current);
setSelectedDetailLoading(true);
setLoadStats({
phase: "complete",
taskId: nextId,
queueMs,
detailMs: 0,
totalMs: performance.now() - startedAt,
chunks: 0,
transcriptRows: 0,
partial: true,
completedAt: new Date(),
});
setRefreshedAt(new Date());
if (trackLoad) trackedLoadInFlightRef.current = false;
void ensureTraceSummary(nextId, true)
.catch((err) => setError(errorText(err, "加载 Codex Trace Summary 失败")));
void loadTaskOverview(apiBaseUrl, nextId, 0, queueFilterId, "", false)
.then((full: any) => {
if (token !== queueLoadTokenRef.current) return;
const fullRows = taskRows(full);
const selected = overviewSelectedTask(full);
if (fullRows.length > 0) {
setTasksData((previous: any) => {
const mergedRows = mergeTaskRowsPreferLatest([taskRows(previous), fullRows], activeSortId);
return { ...previous, statistics: full?.statistics || previous?.statistics, tasks: applyLocalReadStateToRows(mergedRows) };
});
}
if (selected?.id === selectedIdRef.current) {
const transcript = Array.isArray(selected.transcript) ? selected.transcript : [];
publishCachedTask(selected.id, {
...selected,
transcript,
_summaryLoaded: true,
_detailLoaded: transcript.length > 0,
_transcriptPreview: Boolean(full?.selected?.preview),
}, detailLoadTokenRef.current);
}
})
.catch(() => {});
return;
}
if (overviewTask?.id === nextId && overviewTranscript !== null) {
const cached = sessionCacheRef.current.get(nextId);
const existingTranscript = Array.isArray(cached?.task?.transcript) ? cached.task.transcript : [];
@@ -457,29 +457,40 @@ async function queueSummaryForResponse(includeDevReady = true, tasks?: QueueTask
async function queueSummaryForHealth(includeDevReady = true): Promise<JsonValue> {
const summary = queueSummary(includeDevReady, ctx().tasks()) as Record<string, JsonValue>;
if (!ctx().databaseReady()) return summary;
const [totalRows, statusRows, queueStatusRows, unreadRows] = await Promise.all([
ctx().sql<Array<{ total: string | number }>>`SELECT COUNT(*) AS total FROM unidesk_code_queue_tasks`,
ctx().sql<Array<{ status: string; count: string | number }>>`
SELECT status, COUNT(*) AS count
FROM unidesk_code_queue_tasks
GROUP BY status
`,
ctx().sql<Array<{ queue_id: string; status: string; count: string | number }>>`
SELECT queue_id, status, COUNT(*) AS count
FROM unidesk_code_queue_tasks
GROUP BY queue_id, status
`,
ctx().sql<Array<{ queue_id: string; count: string | number }>>`
SELECT queue_id, COUNT(*) AS count
FROM unidesk_code_queue_tasks
WHERE status IN ('succeeded', 'failed', 'canceled')
AND read_at IS NULL
GROUP BY queue_id
`,
]);
const aggregateRows = await ctx().sql<QueueSummaryAggregateRow[]>`
SELECT
(SELECT COUNT(*) FROM unidesk_code_queue_tasks) AS total,
COALESCE((
SELECT jsonb_object_agg(status, count)
FROM (
SELECT status, COUNT(*) AS count
FROM unidesk_code_queue_tasks
GROUP BY status
) AS status_counts
), '{}'::jsonb) AS status_counts,
COALESCE((
SELECT jsonb_agg(jsonb_build_object('queueId', queue_id, 'status', status, 'count', count))
FROM (
SELECT queue_id, status, COUNT(*) AS count
FROM unidesk_code_queue_tasks
GROUP BY queue_id, status
) AS queue_status_counts
), '[]'::jsonb) AS queue_status_counts,
COALESCE((
SELECT jsonb_agg(jsonb_build_object('queueId', queue_id, 'count', count))
FROM (
SELECT queue_id, COUNT(*) AS count
FROM unidesk_code_queue_tasks
WHERE status IN ('succeeded', 'failed', 'canceled')
AND read_at IS NULL
GROUP BY queue_id
) AS unread_counts
), '[]'::jsonb) AS unread_counts
`;
const aggregate = aggregateRows[0] ?? { total: ctx().tasks().length, status_counts: {}, queue_status_counts: [], unread_counts: [] };
const counts: Record<string, number> = {};
for (const row of statusRows) counts[row.status] = Number(row.count);
const unreadByQueue = new Map(unreadRows.map((row) => [ctx().safeQueueId(row.queue_id), Number(row.count)]));
for (const [status, count] of Object.entries(aggregate.status_counts ?? {})) counts[status] = Number(count);
const unreadByQueue = new Map((aggregate.unread_counts ?? []).map((row) => [ctx().safeQueueId(String(row.queueId ?? row.queue_id ?? "")), Number(row.count ?? 0)]));
const summaries = new Map<string, {
name: string;
total: number;
@@ -502,8 +513,8 @@ async function queueSummaryForHealth(includeDevReady = true): Promise<JsonValue>
updatedAt: queue.updatedAt,
});
}
for (const row of queueStatusRows) {
const queueId = ctx().safeQueueId(row.queue_id);
for (const row of aggregate.queue_status_counts ?? []) {
const queueId = ctx().safeQueueId(String(row.queueId ?? row.queue_id ?? ""));
let queue = summaries.get(queueId);
if (queue === undefined) {
queue = {
@@ -518,8 +529,9 @@ async function queueSummaryForHealth(includeDevReady = true): Promise<JsonValue>
};
summaries.set(queueId, queue);
}
const count = Number(row.count);
queue.counts[row.status] = count;
const count = Number(row.count ?? 0);
const status = String(row.status || "");
queue.counts[status] = count;
queue.total += count;
}
for (const [queueId, queue] of summaries) {
@@ -540,7 +552,7 @@ async function queueSummaryForHealth(includeDevReady = true): Promise<JsonValue>
createdAt: queue.createdAt,
updatedAt: queue.updatedAt,
})) as unknown as JsonValue[];
summary.total = Number(totalRows[0]?.total ?? ctx().tasks().length);
summary.total = Number(aggregate.total ?? ctx().tasks().length);
summary.counts = counts as unknown as JsonValue;
summary.unreadTerminal = Array.from(unreadByQueue.values()).reduce((total, count) => total + count, 0);
summary.queues = queues;
@@ -657,6 +669,12 @@ function taskPageRows(filteredTasks: QueueTask[], url: URL, limit: number): {
type TaskIdRow = { id: string; created_at?: Date | string };
type CountRow = { count: string | number };
type QueueSummaryAggregateRow = {
total: string | number;
status_counts: Record<string, string | number> | null;
queue_status_counts: Array<{ queueId?: string; queue_id?: string; status?: string; count?: string | number }> | null;
unread_counts: Array<{ queueId?: string; queue_id?: string; count?: string | number }> | null;
};
type DailyCountRow = { date: string; count: string | number };
type DailyCompletedRow = {
date: string;