Keep async job and chart-cache files across API recreates, freeze jyotish_api_server.py growth, and fail fast with 429 when rectification or high-rigor compute is saturated. Co-authored-by: Cursor <cursoragent@cursor.com>
6.3 KiB
PROGRESS · Python 引擎运行时治理(2026-09-01)
工作树:.worktrees/engine-runtime-hygiene-20260901
分支:codex/engine-runtime-hygiene-20260901
HEAD:80e7736163be684119c03013a07980031468c634(仍等于 origin/staging)
未提交、未推送。未改 frontend/src/app/page.tsx。未改 .gitea/workflows/**。未切分支、未 reset。迁移 squash 按任务书明确延后。
任务 1 · api 命名卷
- 容器
WORKDIR(deploy/railway-api.Dockerfile):/app - 代码路径:
Path(REPO_ROOT) / 'scratch' / 'local' / ...→ 容器内/app/scratch/local - Compose 卷名:
api_scratch - 挂载:
api_scratch:/app/scratch/local(deploy/docker-compose.server.yml的 api 服务) - 项目前缀后的 Docker 卷名:
jyotisha-staging_api_scratch/jyotisha-production_api_scratch - 向后兼容:首次
docker compose up创建命名卷;当前 overlay 数据本就是易失的,无迁移
备份结论(已写入 deploy/README.md)
- Chart cache(
/app/scratch/local/api_chart_cache,默认 TTL 900s)不值得备份;重建比归档便宜。 - Async / high-rigor job 态(
async_jobs/async_jobs.sqlite3/high_rigor_jobs,默认 TTL 3600s)是短生命周期进行中工作,不是恢复单元。 - Staging 加密备份继续只走
deploy/backup-staging-postgres.sh。不要把api_scratch加进该脚本。命名卷的唯一目标是容器重建后缓存与进行中任务还在。
Deploy 脚本: run-staging-deploy.sh / run-production-deploy.sh 未改。docker compose up 会创建并重新挂上命名卷;现有 up -d --remove-orphans 不会 down -v。
Staging 实机三条验收(blocked):需要真正 dispatch 部署后才能 docker volume ls、重启 api 证明 /app/scratch/local 存活、核对 /api/health。Compose 挂载合同已锁在 tests/test_railway_deployment.py。
任务 2 · 冻结 jyotish_api_server.py
- 开工 live
wc -l:11063(任务书 11035 已过时;出生精度合入后又涨了约 28 行) - 本轮薄注册后:11088
- 合同上限:11363(11063 + 300 bugfix slack)
- 测试:
tests/test_api_server_growth_contract.py(注释写明新功能必须开模块) - 已列入
scripts/run_quality_gate.pyCORE_PYTEST_TARGETS - 根
AGENTS.md第 8 节:scripts/jyotish_api_server.pymust not grow;新端点/功能落scripts/模块,主文件只薄注册
任务 3 · 重计算并发闸
新模块 scripts/api_heavy_compute_gate.py。主文件只 import,并在 do_POST 里 acquire/release。GET(含 /api/health 与 job 轮询)不经过闸门。
- 环境变量
JYOTISH_HEAVY_COMPUTE_CONCURRENCY,默认 2(对齐 2 vCPU) JYOTISH_HEAVY_COMPUTE_RETRY_AFTER_SECONDS,默认 2- 饱和:fail-fast,不排队。HTTP 429 +
Retry-After+error_code=ERR_COMPUTE_BUSY
入闸端点
POST /api/rectification/sensitivity_scanPOST /api/active_rectification_eventsPOST /api/active_rectification_events_v4POST /api/rectification/v5/candidate-featuresPOST /api/rectification/v5/scorePOST /api/rectification/v5/diagnosticsPOST /api/rectification/v5/vedastro-validatePOST /api/dynamic_rectification_opportunitiesPOST /api/dynamic_rectification_scorePOST /api/high_rigor_workflowPOST /api/consultation_workflowPOST /api/professional_readingPOST /api/vedastro/range_scanPOST /api/vedastro_gateway/runPOST /api/vedastro_gateway/jobs/{id}/run(前缀匹配)POST /api/thematic_report
不入闸: GET /api/health、城市/位置解析、job 轮询、/api/chart(已有 TTL 缓存 + JYOTISH_ASYNC_JOB_* 有界队列;再叠 429 会误伤常规排盘)、问卷、v5 versions、capability/catalog 等轻量路由。
验证命令与输出
/opt/anaconda3/bin/python3.12 -m pytest \
tests/test_api_server_growth_contract.py \
tests/test_api_heavy_compute_gate.py -v
collected 7 items
tests/test_api_server_growth_contract.py ... [ 42%]
tests/test_api_heavy_compute_gate.py .... [100%]
============================== 7 passed in 0.28s ===============================
饱和用例(limit=1):第二个重请求 429 + Retry-After: 2 + ERR_COMPUTE_BUSY;释放后 200;同期 GET /api/health 与 POST /api/location/resolve 仍 200。
/opt/anaconda3/bin/python3.12 -m pytest tests/test_api_server_security.py -q
# 129 passed, ~90s(仅 datetime.utcnow DeprecationWarning)
/opt/anaconda3/bin/python3.12 -m pytest \
tests/test_runtime_security_p0.py \
tests/test_api_server_script_entrypoint.py -q
# 11 passed
/opt/anaconda3/bin/python3.12 -m pytest \
tests/test_api_async_job_contract.py \
tests/test_railway_deployment.py \
tests/test_api_server_security.py::test_health_endpoint_exposes_runtime_accuracy_metadata \
tests/test_api_server_security.py::test_vedastro_range_scan_endpoint_uses_user_birth_and_returns_controlled_blocked_state \
tests/test_api_server_security.py::test_professional_reading_composes_high_rigor_and_gateway \
tests/test_api_server_growth_contract.py \
tests/test_api_heavy_compute_gate.py -v
# 22 passed in 0.38s
python3 scripts/pre_work_check.py --remote-timeout 8 --command-timeout 45 → status=pass。
未改前端,故未跑 npm test / tsc。未跑完整 scripts/run_quality_gate.py --profile quick(quick 仍会跑 Next.js test/lint/build;本轮前端豁免)。
改动文件
deploy/docker-compose.server.ymldeploy/README.mdAGENTS.mdscripts/jyotish_api_server.py(薄注册;+25 行)scripts/api_heavy_compute_gate.py(新)scripts/run_quality_gate.pytests/test_api_server_growth_contract.py(新)tests/test_api_heavy_compute_gate.py(新)tests/test_railway_deployment.pyPROGRESS-engine-runtime-hygiene-20260901.md(本文件)
未改:deploy/run-staging-deploy.sh、deploy/run-production-deploy.sh、deploy/backup-staging-postgres.sh。
明确未做 / blocked
- Staging/production 实机挂卷、重启存活、
/api/health部署 SHA(需部署窗口)。 - 完整 quick gate(含 frontend runtime)。
- 迁移 squash。
- 把
/api/chart同步路径送进这道闸。 - 提交 / 推送 / 提升
main。