fix: 修连接/句柄泄漏 + 修脚本版本契约 + 去掉 stk_factor 假启用

P1-13 连接池位泄漏(Scripts/bin/backfill.py)
---------------------------------------------
三处 `get_conn()` 都把 `put_conn(conn)` 放在**成功路径**,异常时连接永不归还:
  get_source_map / get_existing_ids / insert_news
连接池有容量上限,异常路径不归还即永久占住池位,反复失败会耗尽池,
表现为后续所有取连接的操作阻塞(与 db_pool 取连接超时修复是同一类问题)。
修法:全部改为 try/finally 无条件归还。
**自查发现并修正一处残留缺陷**:`finally` 里写成 `cur.close(); put_conn(conn)`,
若 close 本身抛错(连接已断时常见)仍会跳过归还 → 改为嵌套 try/finally,
归还作为无条件最后一步。回归用例正是靠这一点抓出来的。

P1-13 后端 stderr 句柄泄漏(Scripts/bin/newsflash_collect.py)
--------------------------------------------------------------
`stderr=open(BACKEND_STDERR_LOG, "w")` 把 open() 返回值直接丢给 Popen,
父进程这份句柄没有任何引用可关 → 每启动一次后端泄漏一个 fd。
改为先存局部变量、Popen 后立即 close(子进程已持有独立 fd 副本,写入不受影响)。

P2-16 bundle-python.sh 版本契约冲突
------------------------------------
`uv venv --python 3.14` 与 .python-version(=3.12) 及所有 pyproject 的
requires-python=">=3.12,<3.13" 冲突。改为读取 .python-version 作为单一事实来源。
同时 `set -e` → `set -eo pipefail`:原先 `uv venv ... | tail -3` 会吞掉失败退出码,
与文件头注释声称的"确保失败中止"相矛盾。
并注明该脚本**当前不在构建链路内**(build-app.sh 未调用,全仓仅文档提及),
避免后人误以为它是打包的一个阶段。

stk_factor / stk_factor_pro 假启用
----------------------------------
config.yaml 与 config/default.yaml 写 `true`,但 fetcher.py:306 对该表显式跳过
(接口限 5 次/天,无法批量)。改为 false 并注明原因。
另外查明:`tables:` 开关只在「未显式指定表」时才生效(fetcher.py:239-243),
调度脚本总是显式传参 → **不能以 config 为准判断某项是否在跑**。

回归
----
Scripts/bin 213 passed(新增 6 条连接归还用例,已证伪:
旧写法下 `test_get_source_map_returns_conn_on_error` 报 assert 0 == 1)、
core 121、tushare 174、akshare 183、kuaixun 407 —— 合计 1098 passed。

本次一并完成的非代码清理
------------------------
- P2-17 陈旧可写 venv:`~/Library/Application Support/FinDataHub/venvs/` 下
  akshare_fetcher(3.14.6, 308M) 与 kuaixun-service(3.14.5, 156M) 两个副本
  来自 v1.4.7 时期,与 bundle 的 3.12 不符、且每次启动刷 WARN。
  已移出(464M → 12K,保留 venv_versions.json)。应用日志本身提示
  "如需 pip install,请在设置中重建可写副本",故可安全清理。
- P2-21 构建残留:findatahub-core/build、findatahub_core.egg-info、
  findatahub_client.egg-info 已移出(移出前先 mv 到 /tmp 再后台删除,规避沙箱批量删除限制)。
This commit is contained in:
FinDataHub committed 2026-09-19 00:27:21 +08:00
1 parent c6d3556b4b
commit f43b442bf1
15 files changed
+264 -132

No files matched your search

+13 -3
View File
@@ -1,8 +1,14 @@
#!/bin/bash
# ==============================================================
# bundle-python.sh — 将 Python 运行时 + akshare-fetcher 打包进 .app
#
# ⚠️ 当前**不在构建链路内**:`Scripts/build-app.sh` 未调用本脚本,
# 全仓仅 Docs/DEVLOG 提到它。保留作为独立打包工具的参考实现。
# 若要重新启用,请先确认它与 build-app.sh 的分工,避免产物重复。
# ==============================================================
set -e
# pipefail:否则 `uv venv ... | tail -3` 这类管道会吞掉失败退出码,
# 与本文件头部注释声称的"确保失败中止"相矛盾。
set -eo pipefail
APP_DIR="${1:-.build/FinDataHub.app}"
PROJECT_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
@@ -25,8 +31,12 @@ else
mkdir -p "${FRAMEWORKS_DIR}"
cd "${PROJECT_ROOT}"
# uv venv 创建独立虚拟环境(与 bundle 内实际运行时保持一致)
uv venv --python 3.14 "${VENV_DIR}" 2>&1 | tail -3
echo " ✅ 虚拟环境已创建"
# 版本必须取 .python-version(=3.12):此前这里写死 3.14,
# 与 .python-version 及所有 pyproject 的 requires-python=">=3.12,<3.13" 冲突,
# 会造出一个与 bundle 内 3.12 不一致的运行时(详见项目记忆"全项目锁定 3.12")。
PY_VER="$(tr -d '[:space:]' < "${PROJECT_ROOT}/.python-version")"
uv venv --python "${PY_VER}" "${VENV_DIR}" 2>&1 | tail -3
echo " ✅ 虚拟环境已创建 (Python ${PY_VER})"
fi
source "${VENV_DIR}/bin/activate"