fix(export): 增加文档级组合复杂度预算与并发渲染限制

针对 PR 审阅 P1「组合复杂度仍可长时间占满导出线程」与 P3「EXPORT_OUTPUT_TOO_LARGE 误标 HTTP 413」:

- plot: FunctionPlot 记录整块 AST 节点数(node_count),parser 累计
- html: 单篇文档累计节点预算 _MAX_TOTAL_PLOT_NODES=8000,超限回退占位
- service: 并发渲染信号量 MAX_CONCURRENT_RENDERS=2,超限额任务排队等待
- docs: 错误码区分同步 HTTP 错误与异步任务错误,EXPORT_OUTPUT_TOO_LARGE 由
  error_code 返回而非 HTTP 413
- 补充节点预算与并发限制两条回归测试(全量 627 通过)

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
yxx
2026-09-06 14:01:29 +08:00
co-authored by Claude Code
parent 124024a547
commit c9c5f81d49
7 changed files with 130 additions and 41 deletions
+14
View File
@@ -269,3 +269,17 @@ def test_html_exporter_limits_function_plot_count() -> None:
assert html.count('<figure class="function-plot">') == 16
assert html.count('<pre class="function-plot">') == 4
assert any("函数图像数量超过上限" in w for w in result.warnings)
def test_html_exporter_limits_total_plot_nodes(monkeypatch) -> None:
# P1:文档级累计 AST 节点预算超限后,后续图像回退占位,防止组合复杂度耗尽 CPU
import app.export.exporters.html as html_mod
monkeypatch.setattr(html_mod, "_MAX_TOTAL_PLOT_NODES", 5)
# 第一个图块 y=x(1 节点)在预算内;第二个图块 y=x+x+x+x(7 节点)累计超限
md = "```function-plot\ny = x\n```\n\n```function-plot\ny = x + x + x + x\n```"
result = asyncio.run(HtmlExporter().export(parse_document(md), ExportOptions()))
html = result.content.decode("utf-8")
assert html.count('<figure class="function-plot">') == 1
assert html.count('<pre class="function-plot">') == 1
assert any("累计复杂度" in w for w in result.warnings)