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