fix(ui): 运行历史的假耗时、以及「下次运行」显示成过去时间

两处显示问题(来自线上页面核对):

1. 耗时列:被重启打断的轮次,finished_at 是 cleanup_orphan_runs 在重启后补上的,
   于是「耗时」把停机时间也算进去了(线上出现过 235s / 687s 这种假数字)。
   改为只有真正扫描过数据的轮次才计算耗时,其余显示 '-' —— 一轮就报错的
   (比如历史上的 SQL 语法错误)同理。

2. 下次运行:两个作业串行跑在同一个调度线程里,前一个耗时长时后一个会排队,
   next_run_at 因此会停在「已经过了」的时刻;直接显示一个过去时间看起来像故障。
   改为:未启用 → 「未启用」;已过期 → 「排队中(<时间> 到期,等待前序作业让出
   线程)」,未到期照常显示。
This commit is contained in:
yml2213
2026-10-02 21:51:37 +08:00
parent 34d667cba0
commit 847ed4539a
+31 -2
View File
@@ -1,3 +1,4 @@
import type { ReactNode } from "react";
import { useCallback, useEffect, useState } from "react";
import {
Alert,
@@ -34,6 +35,28 @@ const STATUS_TAG: Record<string, { color: string; text: string }> = {
skipped: { color: "default", text: "已跳过" },
};
/**
* 下次运行时间:两个作业串行跑在同一个调度线程里,前一个作业耗时长时,
* 后一个会排队等待 —— 于是 next_run_at 会停在「已经过了」的时刻。
* 直接显示一个过去时间看起来像故障,这里标明「排队中」。
*/
function nextRunLabel(job: AutomationJobItem): ReactNode {
if (!job.next_run_at) {
return <Typography.Text type="secondary">未启用</Typography.Text>;
}
const next = new Date(job.next_run_at).getTime();
if (!Number.isFinite(next)) return formatTime(job.next_run_at);
if (next > Date.now()) return formatTime(job.next_run_at);
return (
<span>
<Typography.Text type="warning">排队中</Typography.Text>{" "}
<Typography.Text type="secondary">
({formatTime(job.next_run_at)} 到期,等待前序作业让出线程)
</Typography.Text>
</span>
);
}
function secondsToHours(seconds: number): number {
return Math.round((seconds / 3600) * 10) / 10;
}
@@ -191,7 +214,13 @@ export default function AutomationPage() {
{
title: "耗时",
width: 90,
render: (_, row) => formatDuration(row.started_at, row.finished_at),
render: (_, row) =>
// 没实际扫描过的轮次没有真实耗时:被中断的记录 finished_at 是重启后
// 补上的(见 cleanup_orphan_runs),差值里混入了停机时间,是个假数字;
// 一轮就报错的(如 SQL 语法错误)同理。
row.scanned > 0 && row.finished_at
? formatDuration(row.started_at, row.finished_at)
: "-",
},
{ title: "说明", dataIndex: "message", ellipsis: true },
];
@@ -256,7 +285,7 @@ export default function AutomationPage() {
{formatTime(job.last_run_at)}
</Descriptions.Item>
<Descriptions.Item label="下次运行">
{formatTime(job.next_run_at)}
{nextRunLabel(job)}
</Descriptions.Item>
<Descriptions.Item label="最近结果">
{job.last_status ? (