refactor(status): derive readiness from ingest_state; drop Excel probe & /data
状态盘就绪态 {kind}_ready 改为从持久的 ingest_state 派生(DB 真相、重启不丢),
不再由心跳读 downloads/ Excel、也不在启动时重置:
- 心跳 _fresh_ingest/_ready_flags/_apply_ready:expected/actual_ready=该类今天入库成功;
undelivered_ready=百世原生(今天入库) / 4 站派生(expected ∧ actual)。
- _persist_to_db 入库后调 _refresh_ready 立即派生(省 30s 心跳等待,与心跳同源);
4 站 undelivered 连入 expected+actual,故 ingest_state 补记 expected/actual/undelivered 三行。
- _record_business_date 只写 business_date,不再碰 ready。
- 删 run_heartbeat 的 Excel 探测循环、DATA_FILENAMES、probe_data_file、遗物清理。
- state_store 增 set_business_date / set_ready(仅写单字段,不碰彼此)。
- 删 GET /data/{filename}(前端不再下载原始中转 Excel);/report 保留。
原则:Excel 只作「站点下载→入库」中转,状态/比对一律走 DB。
真机+单元验证:重启后心跳派生(百世今日入库→立即绿、重启不掉灰);韵达 expected-only
时 undelivered 不亮、补 actual 后亮(派生);百世原生;_ready_flags 7 例边界全过。
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -27,7 +27,7 @@ from fastapi import FastAPI, HTTPException
|
||||
from fastapi.responses import FileResponse
|
||||
from pydantic import BaseModel
|
||||
|
||||
from inbound_verify.paths import DOWNLOAD_DIR, OUTPUT_DIR
|
||||
from inbound_verify.paths import OUTPUT_DIR
|
||||
from inbound_verify import state_store
|
||||
from inbound_verify.runtime import (
|
||||
HEARTBEAT_INTERVAL,
|
||||
@@ -417,20 +417,6 @@ def download_report():
|
||||
return FileResponse(path, filename=REPORT_FILE)
|
||||
|
||||
|
||||
@app.get("/data/{filename}")
|
||||
def download_data(filename: str):
|
||||
"""下载 downloads/ 下的数据文件(防路径穿越)。"""
|
||||
if not filename or "/" in filename or "\\" in filename or ".." in filename:
|
||||
raise HTTPException(status_code=400, detail="非法文件名")
|
||||
path = os.path.join(DOWNLOAD_DIR, filename)
|
||||
# 双重校验:解析后绝对路径仍在 DOWNLOAD_DIR 内
|
||||
if not os.path.abspath(path).startswith(os.path.abspath(DOWNLOAD_DIR) + os.sep):
|
||||
raise HTTPException(status_code=400, detail="非法路径")
|
||||
if not os.path.isfile(path):
|
||||
raise HTTPException(status_code=404, detail="文件不存在")
|
||||
return FileResponse(path, filename=filename)
|
||||
|
||||
|
||||
def main():
|
||||
"""服务模式入口。传字符串导入路径(规范写法;不开 reload/workers 时进程内 import,行为等价)。"""
|
||||
uvicorn.run("inbound_verify.cli.server:app", host="0.0.0.0", port=8000)
|
||||
|
||||
Reference in New Issue
Block a user