fix(498-1 렌더러 멈춤): 밀린 버림 차례가 같은 기록을 되받는 finishDrop 고리 그침 — 요구 298-3
- design_pipeline_page finishDrop — lastRun 이 이미 끝난 같은 기록을 돌려주면 다시 부르지 않고 그 기록으로 마침(마이크로태스크 고리 · 렌더러 메모리 4.7 GB 뒤 죽음) - 시험 test_298_3_finishdrop_loop(finishDrop 본문을 떼어 같은 기록 되받기 → 한 번만 · 고치기 전 51 번) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -375,8 +375,10 @@ function createPagePipeline(
|
||||
const finishDrop = async (record: PipelineRunRecord): Promise<string> => {
|
||||
// 뒤 차례(B06 cross 등)에 밀림 · 초안은 그대로 버려짐 — 마지막 차례 끝에서 되돌림(B05 와 같게)
|
||||
const pushed = record.outcome === "dropped" && record.generation !== pipe.generation;
|
||||
if (pushed && dropPending && !pipe.input("route"))
|
||||
return (lastRun as Promise<PipelineRunRecord>).then(finishDrop);
|
||||
if (pushed && dropPending && !pipe.input("route")) {
|
||||
const next = await (lastRun as Promise<PipelineRunRecord>);
|
||||
if (next !== record) return finishDrop(next); // 같은 기록 = 끝난 차례 · 되받으면 끝없는 고리(298-3)
|
||||
}
|
||||
dropPending = false;
|
||||
const routeId = pageSaved.canonRouteId();
|
||||
const stations = pipe.output("ground")?.stations ?? [];
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/* 298-3 노선 [저장] 뒤 렌더러 멈춤 단위검증 헬퍼 — `design_pipeline_page.ts` 의 `finishDrop` 본문을
|
||||
* 그대로 떼어 트랜스파일 · 둘레 칸은 가짜. 밀린 버림 기록(dropped · 옛 차례)을 넘기고 lastRun 이 같은 기록을
|
||||
* 되돌려 줄 때 finishDrop 이 몇 번 불리는지 · 끝나는지. 결과 JSON 을 stdout 으로.
|
||||
*/
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const ts = require(path.join(__dirname, "..", "..", "config", "node_modules", "typescript"));
|
||||
|
||||
const ROOT = path.join(__dirname, "..", "..");
|
||||
const code = fs.readFileSync(
|
||||
path.join(ROOT, "A00_Common", "design", "design_pipeline_page.ts"),
|
||||
"utf8",
|
||||
);
|
||||
const begin = code.indexOf("const finishDrop = async");
|
||||
const end = code.indexOf("\n };", begin) + 5;
|
||||
if (begin < 0 || end < begin) throw new Error("finishDrop 못 찾음");
|
||||
const body = code
|
||||
.slice(begin, end)
|
||||
.replace("const finishDrop = async", "const finishDropInner = async");
|
||||
|
||||
const harness = `
|
||||
let calls = 0;
|
||||
const finishDrop = (record: any): Promise<string> => {
|
||||
calls += 1;
|
||||
if (calls > 50) return Promise.reject(new Error("loop"));
|
||||
return finishDropInner(record);
|
||||
};
|
||||
${body}
|
||||
return { finishDrop, calls: () => calls };
|
||||
`;
|
||||
const js = ts
|
||||
.transpileModule(`(function () {${harness}})`, {
|
||||
compilerOptions: { target: ts.ScriptTarget.ES2022 },
|
||||
})
|
||||
.outputText.replace(/^"use strict";/, "");
|
||||
|
||||
const record = { outcome: "dropped", generation: 3 };
|
||||
const pipe = { generation: 5, input: () => null, output: () => null };
|
||||
let released = 0;
|
||||
const scope = {
|
||||
pipe,
|
||||
dropPending: true,
|
||||
lastRun: Promise.resolve(record), // 이미 끝난 같은 차례 기록
|
||||
pageSaved: { canonRouteId: () => 7, adoptCanon() {} },
|
||||
held: null,
|
||||
options: {},
|
||||
heldSectionDetail: () => null,
|
||||
stationDiff: () => null,
|
||||
adoptAfterDrop() {},
|
||||
publisher: { shown: async () => undefined },
|
||||
releaseWhenQuiet: async () => void (released += 1),
|
||||
};
|
||||
const names = Object.keys(scope);
|
||||
const make = new Function(
|
||||
"scope",
|
||||
`let { ${names.join(", ")} } = scope;\nreturn ${js.trim().replace(/;$/, "")}();`,
|
||||
);
|
||||
const { finishDrop, calls } = make(scope);
|
||||
|
||||
finishDrop(record).then(
|
||||
(why) => console.log(JSON.stringify({ calls: calls(), why, released, record })),
|
||||
(error) => console.log(JSON.stringify({ calls: calls(), error: String(error), released })),
|
||||
);
|
||||
@@ -0,0 +1,25 @@
|
||||
"""298-3 노선 [저장] 뒤 렌더러 멈춤 — 밀린 버림 기록을 lastRun 이 같은 기록으로 되돌려 줘도 finishDrop 은 한 번.
|
||||
|
||||
./venv/Scripts/python.exe -m pytest resources/tester/test_298_3_finishdrop_loop.py -q
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
HELPER = Path(__file__).resolve().parent / "helper_298_3_finishdrop_loop.cjs"
|
||||
|
||||
|
||||
def test_같은_기록_되받기_고리_없음() -> None:
|
||||
run = subprocess.run( # noqa: S603 — 고정 실행 파일
|
||||
["node", str(HELPER)], capture_output=True, text=True, encoding="utf-8", timeout=30
|
||||
)
|
||||
assert run.returncode == 0, run.stderr
|
||||
out = json.loads(run.stdout)
|
||||
assert "error" not in out, out
|
||||
assert out["calls"] == 1
|
||||
assert out["why"] == "dropped" # 밀린 기록 그대로 · 되돌림 없음
|
||||
assert out["released"] == 1
|
||||
assert out["record"]["restored"] is False
|
||||
Reference in New Issue
Block a user