0750f4c41d4569591f0e1cafaa1a6cef10051cac
需求:每天一个日志;历史日志重命名加时间戳后缀并归档;
日志根目录只保留当天文件;已产生的日志全部放进根目录下的
Archive 文件夹。
实现(src/runner.py):
- 新增 DailyFileHandler(logging.FileHandler):
· 当天写入 <log_dir>/sync.log(根目录只留当天文件)。
· 跨天或进程启动时,旧 sync.log 重命名为 sync_YYYYMMDD.log
并移入 <log_dir>/Archive/ 归档。
· emit 时若日期变化自动滚动;额外提供 maybe_rollover()
供主循环每轮主动检查,保证跨天必切(即使本轮无日志输出)。
- setup_logging 改为幂等:清掉已有 handler 再添加,避免重复日志行
(此前 setup_logging 被多次调用会产生重复行,现已免疫)。
- main 循环每轮调用 maybe_rollover,跨天切换时记一行
“日志已切换到新的一天,旧日志归档至 Archive/”。
验证:本地 4 项单测全绿(启动归档旧文件 / 当天写入 /
跨天主动滚动 / 同天不滚动)。
ProcurementVisibilityHub_DataSync
采购执行情况即时数据同步服务。将 169 共享盘上的 Excel(采购执行情况即时数据.xlsx)同步写入两个目标库:
- SQL Server(114 /
CompanyDB,schemaprocurementVisibilityHub,表请购执行) - Access 生产库(
ProcurementVisibilityHub.accdb,表procurementVisibilityHub_请购执行)
采用全量覆盖策略:SQL Server 端 TRUNCATE + INSERT,Access 端 DELETE + INSERT,并写入统一的「导入时间」。
目录结构
| 路径 | 说明 |
|---|---|
config/config.yaml |
运行配置(含 DB 凭据,已被 .gitignore 忽略) |
src/config_loader.py |
读取 YAML 配置、构造 ODBC 连接串 |
src/source_watcher.py |
源文件变化检测(mtime/size)+ 下载到 data/ |
src/excel_parser.py |
解析 xlsx → 行字典,含字段映射与类型转换 |
src/sync_writer.py |
全量写入 SQL Server + Access |
src/runner.py |
主入口:服务循环 / 单次 / 本地联调 / dry-run |
data/ |
源文件历史副本(运行时生成,已忽略) |
logs/sync.log |
运行日志(运行时生成,已忽略) |
环境要求
- Python 3.10+
- 目标主机需安装 ODBC 驱动:
- ODBC Driver 17 for SQL Server(连 114 SQL Server)
- Microsoft Access Driver (*.mdb, *.accdb)(连 Access 生产库)
- 依赖见
requirements.txt:PyYAML、openpyxl、pyodbc
安装
# 1. 创建并激活虚拟环境(项目内)
python -m venv .venv
.\.venv\Scripts\activate # Windows
# source .venv/bin/activate # Linux/macOS
# 2. 安装依赖
pip install -r requirements.txt
# 3. 准备配置(从模板复制后填入真实凭据)
cp config/config.yaml.example config/config.yaml # 若无模板,直接新建 config/config.yaml
⚠️
config/config.yaml含数据库账号密码,不纳入版本管理。如需团队共享,请提交一份config/config.yaml.example(占位凭据),真实配置留本地。
配置说明(config/config.yaml 关键字段)
| 字段 | 说明 |
|---|---|
source.unc_path |
源 Excel 的 UNC 路径(169 共享盘) |
source.local_cache_dir |
本地历史副本目录(默认 data) |
scan.interval_seconds |
服务循环扫描间隔(秒) |
sql_server.* |
SQL Server 连接信息(server/port/database/user/password…) |
access.* |
Access 库路径与表名(DBQ/table) |
field_map |
Excel 列名 → 数据库字段名(仅列名不同者) |
auto_fields |
数据库自动生成字段:id_field(自增不写)、import_time_field(=同步时刻) |
sync.strategy |
同步策略,当前固定 full |
sync.batch_size |
批量插入大小(默认 1000) |
logging |
日志级别与目录 |
使用方式
# 服务循环模式(默认,配合 NSSM 部署为 Windows 服务)
python -m src.runner
# 单次运行后退出
python -m src.runner --once
# 用本地文件作源(跳过 169 下载,便于联调)
python -m src.runner --local X.xlsx
# 仅解析并打印,不写库
python -m src.runner --local X.xlsx --dry-run
# 指定配置文件
python -m src.runner --config config/config.yaml
运行逻辑:检测源 Excel 是否变化(mtime/size),无变化则跳过;有变化则下载副本 → 解析 → 全量写入两个目标库。
运行流程
169 共享 Excel
│ source_watcher 检测变化 + 下载到 data/
▼
excel_parser 解析(字段映射 + 类型转换:float/datetime/int/text)
▼
sync_writer 全量写入
├─ SQL Server:TRUNCATE + 分批 INSERT(fast_executemany,事务提交)
└─ Access: DELETE + 分批 INSERT(autocommit)
▼
logs/sync.log 记录全过程
部署(NSSM 服务)
以 Windows 服务常驻运行(主机 114),由 NSSM 拉起 python -m src.runner 进入循环模式。日志统一写入 logs/sync.log。
常见问题
- 连不上 SQL Server:确认 ODBC Driver 17 已装、114:1433 可达、账号密码正确(
Encrypt/TrustServerCertificate与服务器端匹配)。 - Access 写入失败:确认目标主机装了 Microsoft Access Driver,且
access.dbq路径存在、有写权限。 - 源无变化不执行:属正常行为(基于 mtime/size 的增量跳过);想强制全量可用
--local指定当前文件或删除data/.source_meta.json基准。
Description
Languages
Python
100%