Commit 1bbf0774 by luoqi

fix(plan): selectHits 大数组 spread 炸栈,plans 全量重算 28万患者规模下崩溃

hits.push(...subHits) 把每个元素当实参压栈,V8 实参上限 ~6.5万;华北灌完(host ~28万患者)后
单子场景命中超限 → RangeError: Maximum call stack size exceeded,recompute-plans 中途崩、
无汇总输出。改逐个 push。parser-pipeline 的 metrics.writes.push(...results) 同型隐患
(单资源单批已 5万+ 行)一并修掉。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
parent 67668e9e
Pipeline #3381 failed in 0 seconds
......@@ -208,16 +208,20 @@ export class TreatmentInitiationRecallScenario implements PlanScenarioPlugin {
// 合并/去重(下游 hitsByPatient Map + max 分 + Set 比对)与顺序无关 → 并行 = 结果逐字节相同。
// PAC_RECALL_SUBSCENARIO_CONCURRENCY=N(>1)开并行(分块 Promise.all);默认串行,行为不变。
const conc = Math.max(1, Number(process.env.PAC_RECALL_SUBSCENARIO_CONCURRENCY) || 1);
// ⚠️ 不能 hits.push(...subHits):spread 把每个元素当实参压栈,V8 实参上限 ~6.5万;
// host 患者到 ~28 万后单子场景命中可超限 → RangeError: Maximum call stack size exceeded
// (2026-07-17 华北全量后线上实炸)。改逐个 push,容量无上限。
if (conc > 1) {
for (let i = 0; i < entries.length; i += conc) {
const chunk = await Promise.all(
entries.slice(i, i + conc).map(([subKey, cfg]) => this.runSubScenario(scope, subKey, cfg)),
);
for (const subHits of chunk) hits.push(...subHits);
for (const subHits of chunk) for (const h of subHits) hits.push(h);
}
} else {
for (const [subKey, cfg] of entries) {
hits.push(...(await this.runSubScenario(scope, subKey, cfg)));
const subHits = await this.runSubScenario(scope, subKey, cfg);
for (const h of subHits) hits.push(h);
}
}
this.logger.debug(
......
......@@ -204,8 +204,10 @@ export class ParserPipeline {
// 2. 一次 bulk write,失败降级 per-entry(写一份保证收尾)
try {
const results = await this.writer.bulkWrite(bulkEntries);
metrics.writes.push(...results);
// 逐个 push,不用 push(...results):单资源单批已达 5 万+ 行,spread 实参压栈会炸
// RangeError(V8 上限 ~6.5万;同型 bug 曾炸 plans 的 selectHits,见 scenario 注释)。
for (const r of results) {
metrics.writes.push(r);
switch (r.action) {
case 'created':
metrics.factsCreated++;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment