feat: 优化审计任务UI和错误处理
- 隐藏审计进度对话框中的 pending 状态日志 - 优化仓库扫描任务的状态更新时机 - 增强错误处理:添加连续失败和失败率检测
This commit is contained in:
parent
a250c92182
commit
9d2897773d
|
|
@ -166,8 +166,8 @@ export default function TerminalProgressDialog({
|
||||||
isFirstPoll = false;
|
isFirstPoll = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 只在有变化时显示请求/响应信息
|
// 只在有变化时显示请求/响应信息(跳过 pending 状态)
|
||||||
if (hasDataChange) {
|
if (hasDataChange && task.status !== "pending") {
|
||||||
addLog(`🔄 正在获取任务状态...`, "info");
|
addLog(`🔄 正在获取任务状态...`, "info");
|
||||||
addLog(
|
addLog(
|
||||||
`✓ 状态: ${task.status} | 文件: ${task.scanned_files}/${task.total_files} | 问题: ${task.issues_count} (${requestDuration}ms)`,
|
`✓ 状态: ${task.status} | 文件: ${task.scanned_files}/${task.total_files} | 问题: ${task.issues_count} (${requestDuration}ms)`,
|
||||||
|
|
@ -182,10 +182,7 @@ export default function TerminalProgressDialog({
|
||||||
|
|
||||||
// 检查任务状态
|
// 检查任务状态
|
||||||
if (task.status === "pending") {
|
if (task.status === "pending") {
|
||||||
// 任务待处理(只在状态变化时显示)
|
// 静默跳过 pending 状态,不显示任何日志
|
||||||
if (statusChanged && logs.filter(l => l.message.includes("等待开始执行")).length === 0) {
|
|
||||||
addLog("⏳ 任务已创建,等待开始执行...", "info");
|
|
||||||
}
|
|
||||||
} else if (task.status === "running") {
|
} else if (task.status === "running") {
|
||||||
// 首次进入运行状态
|
// 首次进入运行状态
|
||||||
if (statusChanged && logs.filter(l => l.message.includes("开始扫描")).length === 0) {
|
if (statusChanged && logs.filter(l => l.message.includes("开始扫描")).length === 0) {
|
||||||
|
|
|
||||||
|
|
@ -79,15 +79,7 @@ export async function runRepositoryAudit(params: {
|
||||||
(async () => {
|
(async () => {
|
||||||
console.log(`🎬 后台扫描任务开始执行: ${taskId}`);
|
console.log(`🎬 后台扫描任务开始执行: ${taskId}`);
|
||||||
try {
|
try {
|
||||||
// 更新任务状态为运行中
|
console.log(`📡 任务 ${taskId}: 正在获取仓库文件列表...`);
|
||||||
console.log(`📋 任务 ${taskId}: 开始更新状态为 running`);
|
|
||||||
await api.updateAuditTask(taskId, {
|
|
||||||
status: "running",
|
|
||||||
started_at: new Date().toISOString(),
|
|
||||||
total_files: 0,
|
|
||||||
scanned_files: 0
|
|
||||||
} as any);
|
|
||||||
console.log(`✅ 任务 ${taskId}: 状态已更新为 running`);
|
|
||||||
|
|
||||||
let files: { path: string; url?: string }[] = [];
|
let files: { path: string; url?: string }[] = [];
|
||||||
|
|
||||||
|
|
@ -135,16 +127,23 @@ export async function runRepositoryAudit(params: {
|
||||||
.sort((a, b) => (a.path.length - b.path.length))
|
.sort((a, b) => (a.path.length - b.path.length))
|
||||||
.slice(0, MAX_ANALYZE_FILES);
|
.slice(0, MAX_ANALYZE_FILES);
|
||||||
|
|
||||||
// 初始化进度,设置总文件数
|
// 立即更新状态为 running 并设置总文件数,让用户看到进度
|
||||||
console.log(`📊 任务 ${taskId}: 设置总文件数 ${files.length}`);
|
console.log(`📊 任务 ${taskId}: 获取到 ${files.length} 个文件,开始分析`);
|
||||||
await api.updateAuditTask(taskId, {
|
await api.updateAuditTask(taskId, {
|
||||||
status: "running",
|
status: "running",
|
||||||
|
started_at: new Date().toISOString(),
|
||||||
total_files: files.length,
|
total_files: files.length,
|
||||||
scanned_files: 0
|
scanned_files: 0
|
||||||
} as any);
|
} as any);
|
||||||
|
console.log(`✅ 任务 ${taskId}: 状态已更新为 running,total_files=${files.length}`);
|
||||||
|
|
||||||
let totalFiles = 0, totalLines = 0, createdIssues = 0;
|
let totalFiles = 0, totalLines = 0, createdIssues = 0;
|
||||||
let index = 0;
|
let index = 0;
|
||||||
|
let failedCount = 0; // 失败计数器
|
||||||
|
let consecutiveFailures = 0; // 连续失败计数
|
||||||
|
const MAX_CONSECUTIVE_FAILURES = 5; // 最大连续失败次数
|
||||||
|
const MAX_TOTAL_FAILURES_RATIO = 0.5; // 最大失败率(50%)
|
||||||
|
|
||||||
const worker = async () => {
|
const worker = async () => {
|
||||||
while (true) {
|
while (true) {
|
||||||
const current = index++;
|
const current = index++;
|
||||||
|
|
@ -156,6 +155,18 @@ export async function runRepositoryAudit(params: {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ✓ 检查连续失败次数
|
||||||
|
if (consecutiveFailures >= MAX_CONSECUTIVE_FAILURES) {
|
||||||
|
console.error(`❌ 任务 ${taskId}: 连续失败 ${consecutiveFailures} 次,停止分析`);
|
||||||
|
throw new Error(`连续失败 ${consecutiveFailures} 次,可能是 LLM API 服务异常`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✓ 检查总失败率
|
||||||
|
if (totalFiles > 10 && failedCount / totalFiles > MAX_TOTAL_FAILURES_RATIO) {
|
||||||
|
console.error(`❌ 任务 ${taskId}: 失败率过高 (${Math.round(failedCount / totalFiles * 100)}%),停止分析`);
|
||||||
|
throw new Error(`失败率过高 (${failedCount}/${totalFiles}),建议检查 LLM 配置或切换其他提供商`);
|
||||||
|
}
|
||||||
|
|
||||||
const f = files[current];
|
const f = files[current];
|
||||||
totalFiles++;
|
totalFiles++;
|
||||||
try {
|
try {
|
||||||
|
|
@ -204,6 +215,9 @@ export async function runRepositoryAudit(params: {
|
||||||
} as any);
|
} as any);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 成功:重置连续失败计数
|
||||||
|
consecutiveFailures = 0;
|
||||||
|
|
||||||
// 每分析一个文件都更新进度,确保实时性
|
// 每分析一个文件都更新进度,确保实时性
|
||||||
console.log(`📈 ${repoType}任务 ${taskId}: 进度 ${totalFiles}/${files.length} (${Math.round(totalFiles/files.length*100)}%)`);
|
console.log(`📈 ${repoType}任务 ${taskId}: 进度 ${totalFiles}/${files.length} (${Math.round(totalFiles/files.length*100)}%)`);
|
||||||
await api.updateAuditTask(taskId, {
|
await api.updateAuditTask(taskId, {
|
||||||
|
|
@ -214,14 +228,32 @@ export async function runRepositoryAudit(params: {
|
||||||
issues_count: createdIssues
|
issues_count: createdIssues
|
||||||
} as any);
|
} as any);
|
||||||
} catch (fileError) {
|
} catch (fileError) {
|
||||||
console.error(`分析文件失败:`, fileError);
|
failedCount++;
|
||||||
|
consecutiveFailures++;
|
||||||
|
console.error(`❌ 分析文件失败 (${f.path}): [连续失败${consecutiveFailures}次, 总失败${failedCount}/${totalFiles}]`, fileError);
|
||||||
}
|
}
|
||||||
await new Promise(r=>setTimeout(r, LLM_GAP_MS));
|
await new Promise(r=>setTimeout(r, LLM_GAP_MS));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const pool = Array.from({ length: Math.min(LLM_CONCURRENCY, files.length) }, () => worker());
|
const pool = Array.from({ length: Math.min(LLM_CONCURRENCY, files.length) }, () => worker());
|
||||||
|
|
||||||
|
try {
|
||||||
await Promise.all(pool);
|
await Promise.all(pool);
|
||||||
|
} catch (workerError: any) {
|
||||||
|
// Worker 抛出错误(连续失败或失败率过高)
|
||||||
|
console.error(`❌ 任务 ${taskId} 因错误终止:`, workerError);
|
||||||
|
await api.updateAuditTask(taskId, {
|
||||||
|
status: "failed",
|
||||||
|
total_files: files.length,
|
||||||
|
scanned_files: totalFiles,
|
||||||
|
total_lines: totalLines,
|
||||||
|
issues_count: createdIssues,
|
||||||
|
completed_at: new Date().toISOString()
|
||||||
|
} as any);
|
||||||
|
taskControl.cleanupTask(taskId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 再次检查是否被取消
|
// 再次检查是否被取消
|
||||||
if (taskControl.isCancelled(taskId)) {
|
if (taskControl.isCancelled(taskId)) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue