Harden async task flows and enhance analysis tooling

这个提交包含在:
cryptocommuniums-afk
2026-03-15 08:05:37 +08:00
父节点 585fd5773d
当前提交 cb643ac154
修改 14 个文件,包含 566 行新增33 行删除

查看文件

@@ -37,11 +37,30 @@ function formatStructuredValue(value: unknown) {
}
}
function formatTaskTiming(task: {
createdAt: string | Date;
startedAt?: string | Date | null;
completedAt?: string | Date | null;
}) {
const createdAt = new Date(task.createdAt).getTime();
const startedAt = task.startedAt ? new Date(task.startedAt).getTime() : null;
const completedAt = task.completedAt ? new Date(task.completedAt).getTime() : null;
const durationMs = (completedAt ?? Date.now()) - (startedAt ?? createdAt);
const seconds = Math.max(0, Math.round(durationMs / 1000));
if (seconds < 60) return `${seconds}s`;
const minutes = Math.floor(seconds / 60);
const rest = seconds % 60;
return `${minutes}m ${rest.toString().padStart(2, "0")}s`;
}
export default function Logs() {
const utils = trpc.useUtils();
const taskListQuery = trpc.task.list.useQuery(
{ limit: 50 },
{
retry: 3,
retryDelay: (attempt) => Math.min(1_000 * 2 ** attempt, 8_000),
placeholderData: (previous) => previous,
refetchInterval: (query) => {
const hasActiveTask = (query.state.data ?? []).some((task) => task.status === "queued" || task.status === "running");
return hasActiveTask ? 3_000 : 10_000;
@@ -103,6 +122,16 @@ export default function Logs() {
</AlertDescription>
</Alert>
{taskListQuery.isError ? (
<Alert variant="destructive">
<AlertTriangle className="h-4 w-4" />
<AlertTitle></AlertTitle>
<AlertDescription>
</AlertDescription>
</Alert>
) : null}
<Tabs defaultValue="tasks" className="space-y-4">
<TabsList>
<TabsTrigger value="tasks"></TabsTrigger>
@@ -153,7 +182,9 @@ export default function Logs() {
) : null}
<div className="flex items-center justify-between text-xs text-muted-foreground">
<span> {task.progress}% · {task.attempts}/{task.maxAttempts}</span>
<span>
{task.progress}% · {task.attempts}/{task.maxAttempts} · {formatTaskTiming(task)}
</span>
{task.status === "failed" ? (
<Button
variant="outline"