Merge pull request #2 from modelstudioai/fix/ts-lint

refactor(stress): simplify target definitions and enhance trace ID ha…
This commit is contained in:
Gong Shiqi
2026-05-29 15:03:26 +08:00
committed by GitHub
6 changed files with 63 additions and 26 deletions
@@ -1,7 +1,7 @@
/**
* 压测 target 工厂函数:封装共享逻辑,每个 target 只需声明式配置。
*/
import { mkdirSync, existsSync, readFileSync } from "node:fs";
import { mkdirSync, existsSync } from "node:fs";
import { join } from "node:path";
import { execFile } from "node:child_process";
import { promisify } from "node:util";
+2 -2
View File
@@ -93,12 +93,12 @@ export async function runStressSuite({ globals, forwarded }) {
// Phase 0: 生成共享前置资源
console.error("");
console.error("========== [Phase 0] 生成共享前置资源 ==========");
console.error("========== [Phase 0] 生成前置资源 ==========");
let sharedFixturesDir;
try {
sharedFixturesDir = await generateCombinedFixtures({ suiteRoot, cliPackage: undefined });
} catch (err) {
console.error(`[全量压测] 共享前置资源生成失败: ${err.message}`);
console.error(`[全量压测] 前置资源生成失败: ${err.message}`);
process.exit(1);
}
+12 -2
View File
@@ -13,6 +13,16 @@ export function formatSuccessRate(rate) {
return `${(rate * 100).toFixed(1)}%`;
}
/**
* 用例墙钟耗时:优先 wallClockMs否则 finishedAt - startedAt无效时 0。
* @param {{ wallClockMs?: number, finishedAt?: number, startedAt?: number }} row
*/
function caseWallClockMs(row) {
if (row.wallClockMs != null) return row.wallClockMs;
const delta = row.finishedAt - row.startedAt;
return Number.isFinite(delta) ? delta : 0;
}
/**
* @param {string} suiteRoot
* @param {object[]} rows 各用例 finishStressRun 返回的摘要
@@ -55,7 +65,7 @@ function buildSuiteMarkdown(rows, meta) {
lines.push("| 用例 | 执行时间 | 任务数 | 并发 | 成功 | 失败 | 成功率 | 详细报告 |");
lines.push("|------|----------|--------|------|------|------|--------|--------|");
for (const r of rows) {
const dur = formatDuration(r.wallClockMs ?? r.finishedAt - r.startedAt ?? 0);
const dur = formatDuration(caseWallClockMs(r));
const sub = r.reportPath ? `\`${r.reportPath}\`` : "—";
lines.push(
`| ${escapeTableCell(r.displayName)} | ${dur} | ${r.count ?? "—"} | ${r.concurrency ?? "—"} | ${r.successCount ?? "—"} | ${r.failCount ?? "—"} | ${formatSuccessRate(r.successRate)} | ${sub} |`,
@@ -71,7 +81,7 @@ function buildSuiteMarkdown(rows, meta) {
function buildSuiteHtml(rows, meta) {
const tableRows = rows
.map((r) => {
const dur = formatDuration(r.wallClockMs ?? r.finishedAt - r.startedAt ?? 0);
const dur = formatDuration(caseWallClockMs(r));
const sub = r.reportPath
? `<a href="${escapeHtml(r.reportPath)}">${escapeHtml(r.reportPath)}</a>`
: "—";
+46 -19
View File
@@ -4,6 +4,33 @@
import { extractJsonFromStdout } from "./parsers.mjs";
import { fetchRequestIdByTaskId } from "./fetch-request-id.mjs";
/**
* 将 trace id 字段转为非空字符串;对象等无法可靠转换时返回 undefined。
* @param {unknown} value
* @returns {string | undefined}
*/
function toTraceString(value) {
if (value == null) return undefined;
if (typeof value === "string") {
const trimmed = value.trim();
return trimmed || undefined;
}
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
const trimmed = String(value).trim();
return trimmed || undefined;
}
return undefined;
}
/**
* 将日志字段转为字符串;非 string 时返回空字符串。
* @param {unknown} value
* @returns {string}
*/
function toLogText(value) {
return typeof value === "string" ? value : "";
}
/**
* @param {unknown} data
*/
@@ -18,9 +45,9 @@ export function extractTraceIdsFromJson(data) {
? /** @type {Record<string, unknown>} */ (obj.error)
: undefined;
const requestIdRaw = obj.request_id ?? obj.requestId ?? err?.request_id ?? err?.requestId;
const requestId =
requestIdRaw != null && String(requestIdRaw).trim() ? String(requestIdRaw).trim() : undefined;
const requestId = toTraceString(
obj.request_id ?? obj.requestId ?? err?.request_id ?? err?.requestId,
);
const taskId = formatTaskIdFromJson(obj);
return { requestId, taskId };
@@ -30,28 +57,29 @@ export function extractTraceIdsFromJson(data) {
* @param {Record<string, unknown>} data
*/
function formatTaskIdFromJson(data) {
if (data.task_id != null && String(data.task_id).trim()) {
return String(data.task_id).trim();
}
const single = toTraceString(data.task_id);
if (single) return single;
if (data.task_ids != null) {
return formatTaskIdsValue(data.task_ids);
}
if (Array.isArray(data.videos)) {
const ids = data.videos
.map((v) =>
v && typeof v === "object" ? /** @type {{ task_id?: unknown }} */ (v).task_id : null,
v && typeof v === "object"
? toTraceString(/** @type {{ task_id?: unknown }} */ (v).task_id)
: undefined,
)
.filter((id) => id != null && String(id).trim())
.map((id) => String(id).trim());
.filter((id) => id != null);
if (ids.length > 0) return [...new Set(ids)].join(", ");
}
if (Array.isArray(data.images)) {
const ids = data.images
.map((v) =>
v && typeof v === "object" ? /** @type {{ task_id?: unknown }} */ (v).task_id : null,
v && typeof v === "object"
? toTraceString(/** @type {{ task_id?: unknown }} */ (v).task_id)
: undefined,
)
.filter((id) => id != null && String(id).trim())
.map((id) => String(id).trim());
.filter((id) => id != null);
if (ids.length > 0) return [...new Set(ids)].join(", ");
}
return undefined;
@@ -62,11 +90,10 @@ function formatTaskIdFromJson(data) {
*/
function formatTaskIdsValue(value) {
if (Array.isArray(value)) {
const ids = value.map((v) => String(v).trim()).filter(Boolean);
const ids = value.map((v) => toTraceString(v)).filter((id) => id != null);
return ids.length > 0 ? ids.join(", ") : undefined;
}
if (value != null && String(value).trim()) return String(value).trim();
return undefined;
return toTraceString(value);
}
/**
@@ -186,9 +213,9 @@ export function extractTraceIdsFromLogs(stdout, stderr) {
* @param {Record<string, unknown>} result
*/
export function mergeTraceIds(result) {
const stdout = String(result.stdout ?? "");
const stderr = String(result.stderr ?? "");
const errorText = String(result.error ?? "");
const stdout = toLogText(result.stdout);
const stderr = toLogText(result.stderr);
const errorText = toLogText(result.error);
const combined = `${stdout}\n${stderr}\n${errorText}`;
const data = extractJsonFromStdout(stdout);
@@ -230,7 +257,7 @@ export async function enrichTraceIdsAsync(result) {
if (merged.requestId) return merged;
const taskId = merged.taskId ? String(merged.taskId).split(",")[0].trim() : "";
const taskId = toTraceString(merged.taskId)?.split(",")[0]?.trim() ?? "";
if (!taskId) return merged;
if (process.env.STRESS_FETCH_REQUEST_ID === "0") return merged;
@@ -30,7 +30,7 @@ export const runStress = defineStressTarget({
generatePrompt: (idx) => `[ASR-${idx}-${Date.now().toString(36)}]`,
buildCliArgs: ({ MODEL, CLI_TIMEOUT_SEC, POLL_INTERVAL, fixtureRef, runDir, index }) => [
buildCliArgs: ({ MODEL, CLI_TIMEOUT_SEC, POLL_INTERVAL, fixtureRef, runDir }) => [
"speech",
"recognize",
"--model",
@@ -88,7 +88,7 @@ export const runStress = defineStressTarget({
String(POLL_INTERVAL),
],
buildBaseRecord: ({ runDir, index, extraParams }) => ({
buildBaseRecord: ({ runDir, index }) => ({
downloadPath: join(runDir, `video_${String(index + 1).padStart(3, "0")}.mp4`),
}),