feat: 算法升级、整车配准集成与性能分析文档

算法更新: delivery v1.2.1、平整度v1.5、测距v2.2、整车配准v1.3
适配器: vehicle-registration 新增、各算法 manifest 和 adapter 更新
后端: taskCadFiles/source 字段迁移、derivedPointClouds 注册、取消任务联动
前端: ElapsedTime 时长显示、两步算法流程、canRun 逻辑修复
文档: 新增5份算法性能分析报告
This commit is contained in:
2026-06-25 08:22:20 +00:00
parent cec0766e67
commit 29f1d45d66
266 changed files with 1311475 additions and 2846 deletions

View File

@@ -35,7 +35,7 @@ class ConcurrencyPool {
private running = 0;
private queue: PendingJob[] = [];
private readonly limit: number;
private readonly activeChildren = new Set<ChildProcess>();
private readonly activeChildren = new Map<number, ChildProcess>(); // resultId → child
constructor(limit: number) {
this.limit = Math.max(1, limit);
@@ -52,6 +52,49 @@ class ConcurrencyPool {
});
}
/** 取消指定 resultId 的 job:若在队列中直接移除;若已在运行则 kill 子进程。 */
cancel(resultId: number): boolean {
// 先从队列里找(还未开始执行)
const idx = this.queue.findIndex((j) => j.resultId === resultId);
if (idx !== -1) {
const [job] = this.queue.splice(idx, 1);
job.resolve(); // 让等待方正常退出
return true;
}
// 再找正在运行的子进程
const child = this.activeChildren.get(resultId);
if (child) {
child.kill('SIGKILL');
return true;
}
return false;
}
/** 取消某个 taskId 下所有 job(删除任务时用)。返回被取消的 resultId 数组。 */
cancelByTask(taskId: number): number[] {
const cancelled: number[] = [];
// 队列中移除
const keep: PendingJob[] = [];
for (const job of this.queue) {
if (job.taskId === taskId) {
job.resolve();
cancelled.push(job.resultId);
} else {
keep.push(job);
}
}
this.queue = keep;
// 运行中 kill
for (const [resultId, child] of this.activeChildren) {
const jobTaskId = (child as ChildProcess & { _taskId?: number })._taskId;
if (jobTaskId === taskId) {
child.kill('SIGKILL');
cancelled.push(resultId);
}
}
return cancelled;
}
private pump(): void {
while (this.running < this.limit && this.queue.length > 0) {
const next = this.queue.shift()!;
@@ -79,14 +122,16 @@ class ConcurrencyPool {
stdio: ['ignore', 'inherit', 'inherit', 'ipc'],
execArgv: isProd ? [] : ['--import', 'tsx'],
});
this.activeChildren.add(child);
// 把 taskId 附到 child 上,cancelByTask 用
(child as ChildProcess & { _taskId?: number })._taskId = job.taskId;
this.activeChildren.set(job.resultId, child);
return new Promise<void>((resolve) => {
child.on('error', (err) => {
console.error('[AlgorithmJob] fork 失败:', err);
});
child.on('exit', (code, signal) => {
this.activeChildren.delete(child);
this.activeChildren.delete(job.resultId);
if (code !== 0 && code != null) {
console.error(
`[AlgorithmJob] 子进程退出 code=${code} signal=${signal ?? ''} pluginId=${job.pluginId} resultId=${job.resultId}`,
@@ -128,3 +173,13 @@ export function enqueueAlgorithmJob(
export function algorithmJobStats() {
return pool.stats;
}
/** 取消单个分析结果对应的 job(删除分析结果时调用)。 */
export function cancelAlgorithmJob(resultId: number): boolean {
return pool.cancel(resultId);
}
/** 取消某检测任务下所有 job(删除任务时调用)。 */
export function cancelAlgorithmJobsByTask(taskId: number): number[] {
return pool.cancelByTask(taskId);
}