From 93af27d1e1271cd432b36606030d3bae4859f666 Mon Sep 17 00:00:00 2001 From: "34047007@qq.com" <34047007@qq.com> Date: Fri, 7 Aug 2026 22:44:03 +0800 Subject: [PATCH] =?UTF-8?q?checkpoint:=20=E5=9F=BA=E5=BB=BA=E4=B8=8E?= =?UTF-8?q?=E7=A1=AE=E5=AE=9A=E6=80=A7=E6=96=87=E6=A1=A3=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E2=80=94=E2=80=94=E8=BF=90=E8=90=A5=E6=89=8B=E5=86=8C=203.1.0?= =?UTF-8?q?=20+=20=E5=BC=95=E6=93=8E=E5=AE=9E=E6=96=BD=E8=AE=B0=E5=BD=95?= =?UTF-8?q?=2018.23?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 运营手册升 3.1.0:定时任务 jobstore 落 PG 说明、SQLite 彻底清理、require_redis 显式 503 守卫行、备份口径同步。实施记录追加 18.23:引擎确定性修复(系谱按 id 规范排序, 消除 DB 行序对 MME 布局影响,根因链 + 验证)。 --- doc/桃育种系统生产上线与运营手册.md | 16 ++++++++++------ doc/桃育种系统统计引擎实施记录.md | 15 +++++++++++++++ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/doc/桃育种系统生产上线与运营手册.md b/doc/桃育种系统生产上线与运营手册.md index 48eefa0..f70e380 100644 --- a/doc/桃育种系统生产上线与运营手册.md +++ b/doc/桃育种系统生产上线与运营手册.md @@ -1,8 +1,9 @@ # 数字化桃育种系统 生产上线与运营手册 -> 版本:3.0.1 适用:生产(Docker Compose)部署 +> 版本:3.1.0 适用:生产(Docker Compose)部署 > 前置阅读:`docker/README.md`(部署操作)、`doc/桃育种系统模块扩展需求规格.md`(功能规格,v2.7,2026-08-04) > 本文档基于 2026-08-04 安全加固后的代码与配置撰写,上线前请逐项核对。 +> 3.1.0(2026-08-07):定时任务 jobstore 落 PostgreSQL、SQLite 彻底清理、Redis 降级守卫完备(存储类接口显式 503),详见各节标注。 --- @@ -16,7 +17,7 @@ | 反向代理 | nginx 1.25-alpine | 容器 `nginx` | TLS 终结、HTTP→HTTPS、API 反代、限流 | | 后端 | FastAPI + SQLAlchemy async + Redis | 容器 `backend` | `python main.py run --env=prod` | | 数据库 | PostgreSQL 16 | 容器 `postgres` | 见 §3 | -| 缓存 | Redis 7 | 容器 `redis` | 会话、验证码、登录锁定计数、系统参数缓存 | +| 缓存 | Redis 7 | 容器 `redis` | 会话、验证码、登录锁定计数、系统参数缓存(**定时任务 jobstore 已落 PG**,不依赖 Redis,见 §3) | ### 1.2 端口暴露(已收紧到本机回环) @@ -32,8 +33,8 @@ ### 1.3 数据流 ``` -浏览器 ──443──> nginx(TLS/限流/反代)──8001──> backend ──> PostgreSQL 16 - └──> Redis +浏览器 ──443──> nginx(TLS/限流/反代)──8001──> backend ──> PostgreSQL 16(业务数据 + 定时任务 jobstore) + └──> Redis(会话/缓存;降级时参数/字典读接口回源 DB) ``` --- @@ -89,6 +90,8 @@ Docker Compose 使用(`docker compose --env-file .env up -d`)。必填项缺 生产固定使用 PostgreSQL 16,与开发环境(`localhost:5432`,库/角色 `dpb`)一致,可用 `pg_dump`/`pg_restore` 无缝迁移。 +**定时任务 jobstore 落 PG(3.1.0)**:调度器默认 jobstore 为 `apscheduler_jobs` 表(SQLAlchemyJobStore),任务定义持久化于主库——重启/升级后由 apscheduler 原生机制自动恢复,**不依赖 Redis**(多 Worker 场景本系统不适用,故不做 Redis jobstore)。该表随主库每日备份(§6.2),备份即含任务定义。 + `docker/docker-compose.yaml` 已编排 `postgres:16` 服务: | 配置 | 值 | @@ -201,6 +204,7 @@ docker compose ps # 全部 healthy 为佳 | 生产配置 fail-safe | SECRET_KEY 非默认/≥32 位、DEBUG=false、CORS 非空,否则**拒绝启动** | `setting.py` | | 日志脱敏 | 密码/token/验证码等字段掩码为 `***`;refresh/logout 裸 body 整体掩码 | `router_class.py` | | 登录暴力破解 | 同一用户名+IP 连续失败 5 次锁定 15 分钟(Redis);Redis 故障时自动降级不锁死 | `auth/service.py` | +| 存储类接口降级守卫 | AI配置/在线监控/缓存监控/验证码接口依赖 `require_redis`:Redis 不可用显式 **503**(而非 500/静默空数据);参数/字典读接口回源数据库;调度任务 jobstore 已落 PG 不受影响 | `dependencies.py` | | 生产关闭文档 | `/docs`、`/redoc` 生产不注册 | `init_app.py` | | 客户端 IP 防伪造 | 默认不信任 XFF;`IP_TRUST_PROXY_HEADERS=true` 才读取 | `ip_local_util.py` | | 端口收内网 | 数据库/Redis/后端均绑 `127.0.0.1` | `docker-compose.yaml` | @@ -239,14 +243,14 @@ docker compose logs -f backend # 实时日志 ### 6.2 备份与恢复 -**备份优先级**:数据库 > 上传文件 > 配置 > 前端产物(可重建)> Redis(会话可重建)。 +**备份优先级**:数据库 > 上传文件 > 配置 > 前端产物(可重建)> Redis(会话可重建;定时任务 jobstore 已落 PG,随数据库备份)。 | 数据 | 位置 | 策略 | |------|------|------| | 数据库(核心) | 数据库卷 | 每日全量 + 保留 7~14 天,异地一份 | | 上传文件 | `backend/static/upload`(容器内 `/home/static/upload`) | 每日增量同步 | | 配置 | `docker/.env`、`backend/env/.env.prod` | 每次变更后备份 | -| Redis | 会话/缓存 | 无需备份(丢失仅踢下线) | +| Redis | 会话/缓存 | 无需备份(丢失仅踢下线;定时任务已落 PG,不在 Redis) | **PostgreSQL 每日备份**(宿主机 crontab 示例): diff --git a/doc/桃育种系统统计引擎实施记录.md b/doc/桃育种系统统计引擎实施记录.md index 3416610..423f1dd 100644 --- a/doc/桃育种系统统计引擎实施记录.md +++ b/doc/桃育种系统统计引擎实施记录.md @@ -2095,3 +2095,18 @@ PYTHONIOENCODING=utf-8 ENVIRONMENT=dev PYTHONPATH=backend python Temp/claude/e2e **③ 授粉窗口规划(window-plan)**:新端点 `GET /bre/pollen/window-plan?window_start=&window_end=`(controller + service.window_plan,纯计算不落库)。`_project_bloom(g, ref_year)` 把花期投影到窗口起始年:结构化区间按年际月日(桃花期 3-4 月单年窗口假设),缺区间 fallback `_BLOOM_TIER_SPAN`(5 档 → 代表区间,粗粒度标注)。花期种质给花粉覆盖三态 `covered`(整段有批次 `collect<=bs and expiry>=be`)/`partial`/`none`(无覆盖 → n_need_pollen + 提示需采粉贮藏或同期授粉);库存侧给批次窗口状态 `full`(全程覆盖)/`expiring`(窗口内到期)/`entering`(窗口内采集、有效期出窗)/`expired`(窗口前失效)/`not_started`(窗口后采集)。窗口反向 409。前端 pollen 页顶部「授粉窗口规划」卡片:daterange 默认本年度/次年花期(3-4 月在当年、否则次年 03-01~04-30)+ 生成按钮 + 缺粉 alert + 花期覆盖表 + 库存状态表;pollen.ts 加 `getWindowPlan` + `PollenWindowPlan`/`PollenBloomItem`/`PollenInventoryItem`/`PollenLotRef` 类型。 **验证**:`e2e_o1_bloom_20260805.py` 探针全过——① CreateSchema→CRUD 双 Date 列落库;② 6 种质 15 对(重叠/错开/需采粉贮藏三类 + 档位 fallback mid×very_early→store + 区间×档位混合对→unknown,flags 仅非重叠进警示);③ 窗口 A(03-05~04-08)花期覆盖三态 covered/partial/none + 档位投影种质、窗口 B(03-10~03-30)库存五态 full/expiring/entering/expired/not_started + 窗口反向 409。`vue-tsc` EXIT=0。全量回归 + `run_ci.py` EXIT=0 零回归。版本连锁:4 e2e 探针(statsflow/spatial_sparse×2/prediction_rigor/mendelian_persist)+ o234 tc 断言 v2.29→v2.30。备份镜像 `Temp/claude/backup_o1_bloom_20260805/`。 + +# 18.23 统计引擎确定性修复:系谱按 id 规范排序,消除 DB 行序对 MME 布局的影响(2026-08-07,无版本变更) + +> 背景:全量回归**间歇失败**(`run_regression` 串跑 70/72,`e2e_prediction_rigor` 偶发 acc 0.406 vs 期望 0.405、`e2e_spatial_sparse` 偶发 EBV diff 0.78)——单跑稳定、只在全量串跑出现,属典型的非确定性可重现难题。系统排查逐层排除 DB 残留/序列/并发后定位到引擎本身。 + +**根因链(三层)**: +1. **引擎输入顺序敏感**:`blup._order_pedigree` 保持调用方输入顺序 → MME 变量布局(个体序号)随输入序变化。平似然/退化数据(真实观测稀少、似然面平坦)上,golden-section/二分搜索会被**末位浮点噪声**带偏到任意 h²——同内容不同序实测 **h²=0.616 vs 0.237**(实测 20x 同输入逐位一致、乱序即变)。 +2. **服务层行序不固定**:`statistics/service.py` 从 DB 构建系谱**无 ORDER BY**(`group_by(obs.tree_id)` 聚合后行序由执行计划决定),行序在运行间漂移 → 引擎输入序漂移 → 结果不重现。 +3. **双舍入边界**:服务层 accuracy 存储 `numeric(5,3)`(3 位舍入),探针由 `numeric(6,4)` 可靠性(6 位)再舍 3 位——真值恰落在 3 位舍入边界时可差 **0.001**(如 0.408 vs 0.409),1e-4 容差比自身的双舍入预算还紧。 + +**修复(`backend/scripts/breeding_stats/blup.py`)**: +- `_order_pedigree` 改为对 **base 与同世代并列个体均按 id 确定性排序**(`sorted(base, key=str)` / `sorted(non_base, key=lambda it: str(it[0]))`),输入顺序不参与计算——同内容输入必逐位同输出。单 chokepoint 收口全部 6 个调用点(solve / solve_spatial / solve_multi / rrblup / bayesb / relationship_matrix),服务层 DB 行序不再影响任何引擎入口。 +- `e2e_prediction_rigor` 断言容差 1e-4 → **2e-3**(匹配双舍入预算,注释写明依据)。 + +**验证**:同输入 20x 逐位一致;打乱输入顺序输出仍逐位一致;prediction_rigor 6 次串跑稳定 acc=0.408;全量回归 `run_regression` **72/72 稳定通过**(含正式 tc 套件)。**附带收益**:同内容输入跨运行可复现,与 MLOps 溯源(input_hash 语义)一致,任何调用方从 DB 取行序不再影响结果。