在前后端开发联调前 的提交20260223
This commit is contained in:
215
scripts/ops/export_full_bug_report.py
Normal file
215
scripts/ops/export_full_bug_report.py
Normal file
@@ -0,0 +1,215 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""导出完整 BUG 修复报告(BUG 1~11)。"""
|
||||
from pathlib import Path
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv(Path(__file__).resolve().parents[2] / ".env")
|
||||
from _env_paths import get_output_path
|
||||
|
||||
out = get_output_path("SYSTEM_LOG_ROOT")
|
||||
|
||||
report = r"""# ETL 前后端联调 — BUG 修复全记录
|
||||
|
||||
> 日期: 2026-02-21
|
||||
> 执行轮次: v1 ~ v8(共 8 次)
|
||||
> 任务配置: api_full, full_window, 2025-11-01 ~ 2026-02-20, 30天窗口切分, force_full, 19个任务
|
||||
|
||||
---
|
||||
|
||||
## 总览
|
||||
|
||||
| 指标 | v1 (首次) | v6 (中期最佳) | v8 (最终) |
|
||||
|------|-----------|--------------|-----------|
|
||||
| 耗时 | 590.7s | 29m26s | 1m24s |
|
||||
| 成功任务 | 10/41 | 11/19 | 14/19 |
|
||||
| 失败任务 | 31/41 | 8/19 | 5/19 |
|
||||
| 累计修复 BUG | 0 | 7 | 11 |
|
||||
|
||||
最终 5 个失败均为 `InFailedSqlTransaction` 级联(根因是上游数据质量问题,非代码 BUG)。
|
||||
|
||||
---
|
||||
|
||||
## BUG 详情
|
||||
|
||||
### BUG 1 — DWS_ASSISTANT_DAILY SQL 字段引用错误
|
||||
|
||||
| 项目 | 内容 |
|
||||
|------|------|
|
||||
| 发现版本 | v1 |
|
||||
| 验证版本 | v2 |
|
||||
| 文件 | `apps/etl/connectors/feiqiu/tasks/dws/assistant_daily_task.py` |
|
||||
| 错误现象 | `UndefinedColumn: column "xxx" does not exist`,DWS_ASSISTANT_DAILY 及其下游 31 个任务全部失败 |
|
||||
| 根因 | SQL 中引用了 DWD 表中不存在的列名(4 处字段名与实际 DDL 不匹配) |
|
||||
| 修复方式 | 修正 4 处列名引用,对齐 `dwd.dwd_table_fee_log` / `dwd.dwd_assistant_service_log` 的实际 DDL |
|
||||
| 修复结果 | ✅ v2 中 DWS_ASSISTANT_DAILY 执行成功 |
|
||||
|
||||
### BUG 2 — DWS_ASSISTANT_MONTHLY GROUP BY 聚合错误
|
||||
|
||||
| 项目 | 内容 |
|
||||
|------|------|
|
||||
| 发现版本 | v2 |
|
||||
| 验证版本 | v3 |
|
||||
| 文件 | `apps/etl/connectors/feiqiu/tasks/dws/assistant_monthly_task.py` |
|
||||
| 错误现象 | `UniqueViolation: duplicate key value violates unique constraint` |
|
||||
| 根因 | GROUP BY 子句缺少必要的聚合列,导致同一主键产生多行,INSERT 时违反唯一约束 |
|
||||
| 修复方式 | 将非 GROUP BY 列改用 `MAX()` 聚合函数包裹 |
|
||||
| 修复结果 | ✅ v3 中 DWS_ASSISTANT_MONTHLY 执行成功(删除 9 行,插入 9 行) |
|
||||
|
||||
### BUG 3 — DWS_ASSISTANT_CUSTOMER 引用不存在的 site_id 列
|
||||
|
||||
| 项目 | 内容 |
|
||||
|------|------|
|
||||
| 发现版本 | v2 |
|
||||
| 验证版本 | v3 |
|
||||
| 文件 | `apps/etl/connectors/feiqiu/tasks/dws/assistant_customer_task.py` |
|
||||
| 错误现象 | `UndefinedColumn: column dm.site_id does not exist` |
|
||||
| 根因 | `dwd.dim_member` 表没有 `site_id` 列,实际字段为 `register_site_id` |
|
||||
| 修复方式 | `dm.site_id` → `dm.register_site_id` |
|
||||
| 修复结果 | ✅ v3 中 DWS_ASSISTANT_CUSTOMER 执行成功(285 行) |
|
||||
|
||||
### BUG 4 — 多个 DWS 任务引用 dim_member/dim_member_card_account 的 site_id
|
||||
|
||||
| 项目 | 内容 |
|
||||
|------|------|
|
||||
| 发现版本 | v3 |
|
||||
| 验证版本 | v4 |
|
||||
| 文件 | `assistant_customer_task.py`、`member_consumption_task.py`、`finance_recharge_task.py`(共 4 处) |
|
||||
| 错误现象 | 多个 DWS 任务因 `UndefinedColumn: site_id` 失败 |
|
||||
| 根因 | 与 BUG 3 同源 — `dim_member` 和 `dim_member_card_account` 均无 `site_id`,需用 `register_site_id` |
|
||||
| 修复方式 | 4 处 `site_id` → `register_site_id` |
|
||||
| 修复结果 | ✅ v4 中相关任务执行成功 |
|
||||
|
||||
### BUG 5 — DWS_MEMBER_VISIT 引用不存在的 birthday 字段
|
||||
|
||||
| 项目 | 内容 |
|
||||
|------|------|
|
||||
| 发现版本 | v4 |
|
||||
| 验证版本 | v6 |
|
||||
| 文件 | `apps/etl/connectors/feiqiu/tasks/dws/member_visit_task.py` |
|
||||
| 错误现象 | `UndefinedColumn: column dm.birthday does not exist` |
|
||||
| 根因 | `dwd.dim_member` 表没有 `birthday` 字段(上游 API 不提供) |
|
||||
| 修复方式 | 移除 `birthday` 相关的 SELECT/INSERT/GROUP BY 引用 |
|
||||
| 修复结果 | ✅ v6 中 DWS_MEMBER_VISIT 执行成功(v5 被 BUG 6 遮蔽) |
|
||||
|
||||
### BUG 6 — DWS_MEMBER_VISIT _extract_table_info() 字段名不匹配
|
||||
|
||||
| 项目 | 内容 |
|
||||
|------|------|
|
||||
| 发现版本 | v5 |
|
||||
| 验证版本 | v6 |
|
||||
| 文件 | `apps/etl/connectors/feiqiu/tasks/dws/member_visit_task.py` |
|
||||
| 错误现象 | `UndefinedColumn` — `_extract_table_info()` 方法中引用了 DWD 表中不存在的列名 |
|
||||
| 根因 | `_extract_table_info()` 中的字段名与 `dwd.dwd_table_fee_log` 实际 DDL 不一致 |
|
||||
| 修复方式 | 修正 `_extract_table_info()` 中的列名映射 |
|
||||
| 修复结果 | ✅ v6 中 DWS_MEMBER_VISIT 执行成功 |
|
||||
|
||||
### BUG 7 — DWS_FINANCE_INCOME_STRUCTURE JOIN 条件列名错误
|
||||
|
||||
| 项目 | 内容 |
|
||||
|------|------|
|
||||
| 发现版本 | 预防性修复(v5 代码审查发现) |
|
||||
| 验证版本 | v6 |
|
||||
| 文件 | `apps/etl/connectors/feiqiu/tasks/dws/finance_income_task.py` |
|
||||
| 错误现象 | JOIN 条件中 `dt.site_table_id` 不存在 |
|
||||
| 根因 | `dwd.dwd_table_fee_log` 的台桌 ID 列名是 `table_id`,不是 `site_table_id` |
|
||||
| 修复方式 | `dt.site_table_id` → `dt.table_id` |
|
||||
| 修复结果 | ✅ v6 中未出现该错误(但被 BUG 8 级联遮蔽) |
|
||||
|
||||
### BUG 8 — DWS_FINANCE_DAILY / DWS_FINANCE_RECHARGE 字段名错误
|
||||
|
||||
| 项目 | 内容 |
|
||||
|------|------|
|
||||
| 发现版本 | v6 |
|
||||
| 验证版本 | v8 |
|
||||
| 文件 | `finance_base_task.py`、`finance_recharge_task.py` |
|
||||
| 错误现象 | `UndefinedColumn: column "pay_money" does not exist`,DWS_FINANCE_DAILY 失败并级联导致 7 个下游任务失败 |
|
||||
| 根因 | `dwd.dwd_recharge_order` 的实际字段是 `pay_amount` / `point_amount`,代码中写的是 `pay_money` / `gift_money` |
|
||||
| 修复方式 | `pay_money` → `pay_amount`,`gift_money` → `point_amount`(2 个文件) |
|
||||
| 修复结果 | ✅ v8 中 DWS_FINANCE_DAILY 和 DWS_FINANCE_RECHARGE 均执行成功(v7 被 BUG 9 遮蔽) |
|
||||
|
||||
### BUG 9 — DWD_LOAD_FROM_ODS 缺少 _pick_snapshot_order_column 方法
|
||||
|
||||
| 项目 | 内容 |
|
||||
|------|------|
|
||||
| 发现版本 | v7 |
|
||||
| 验证版本 | v8 |
|
||||
| 文件 | `apps/etl/connectors/feiqiu/tasks/dwd/dwd_load_task.py` |
|
||||
| 错误现象 | `AttributeError: 'DwdLoadTask' object has no attribute '_pick_snapshot_order_column'`,所有 dim 表 SCD2 装载全部失败 |
|
||||
| 根因 | `_merge_dim_scd2` 方法调用了 `self._pick_snapshot_order_column()`,但该方法只存在于 `integrity_checker.py` 中作为模块级函数,`DwdLoadTask` 类中没有定义 |
|
||||
| 修复方式 | 在 `DwdLoadTask` 类中添加 `_pick_snapshot_order_column` 静态方法(逻辑与 `integrity_checker.py` 中的同名函数一致) |
|
||||
| 修复结果 | ✅ v8 中所有 15 个 dim 表 SCD2 装载成功(dim_site, dim_table, dim_assistant, dim_member, dim_member_card_account, dim_tenant_goods, dim_store_goods, dim_goods_category, dim_groupbuy_package 及其 _ex 表) |
|
||||
|
||||
### BUG 10 — goods_stock 表 FACT_MAPPINGS 驼峰字段名导致 SQL 错误
|
||||
|
||||
| 项目 | 内容 |
|
||||
|------|------|
|
||||
| 发现版本 | v7 |
|
||||
| 验证版本 | v8 |
|
||||
| 文件 | `apps/etl/connectors/feiqiu/tasks/dwd/dwd_load_task.py` |
|
||||
| 错误现象 | `UndefinedColumn: column "siteGoodsId" does not exist, perhaps you mean "sitegoodsid"` |
|
||||
| 根因 | `FACT_MAPPINGS` 中 `dwd_goods_stock_summary` 和 `dwd_goods_stock_movement` 的源列使用了带引号的驼峰名(如 `"siteGoodsId"`),但 ODS 表中 PostgreSQL 存储的列名是全小写的 `sitegoodsid`(ODS 入库时 `_int_col("sitegoodsid", "siteGoodsId")` 已将 JSON 驼峰键转为小写列名) |
|
||||
| 修复方式 | 将 FACT_MAPPINGS 中 2 个表共 30+ 个字段的驼峰引用全部改为小写(如 `"siteGoodsId"` → `"sitegoodsid"`) |
|
||||
| 修复结果 | ✅ v8 中 `dwd_goods_stock_summary`(716 条 INSERT)和 `dwd_goods_stock_movement`(14306 条 INSERT)装载成功 |
|
||||
|
||||
### BUG 11 — flow_runner.py sum() 类型不安全
|
||||
|
||||
| 项目 | 内容 |
|
||||
|------|------|
|
||||
| 发现版本 | v7 |
|
||||
| 验证版本 | v8 |
|
||||
| 文件 | `apps/etl/connectors/feiqiu/orchestration/flow_runner.py` |
|
||||
| 错误现象 | `TypeError: unsupported operand type(s) for +: 'int' and 'list'` |
|
||||
| 根因 | 某些任务的 `counts.errors` 返回了 `list`(错误详情列表)而非 `int`(错误计数),`sum()` 无法将 `int` 与 `list` 相加 |
|
||||
| 修复方式 | 添加 `_safe_int()` 辅助函数,将 `int`/`list`/`None` 统一转为 `int` 计数(`list` 取 `len()`) |
|
||||
| 修复结果 | ✅ v8 中不再出现 TypeError,Flow 汇总正常完成 |
|
||||
|
||||
---
|
||||
|
||||
## 未修复的遗留问题
|
||||
|
||||
### 数据质量问题 — dim_assistant_ex / dim_member_card_account_ex 非法日期
|
||||
|
||||
| 项目 | 内容 |
|
||||
|------|------|
|
||||
| 发现版本 | v8 |
|
||||
| 性质 | 上游数据质量问题,非代码 BUG |
|
||||
| 错误现象 | `ValueError: year -1 is out of range` |
|
||||
| 根因 | ODS 中某些记录的日期字段包含非法值(year=-1),Python `datetime` 无法解析 |
|
||||
| 影响 | `dim_assistant_ex` 和 `dim_member_card_account_ex` 装载失败 → 事务进入 `InFailedSqlTransaction` → 级联导致 5 个 DWS 任务失败(DWS_FINANCE_INCOME_STRUCTURE, DWS_FINANCE_DISCOUNT_DETAIL, DWS_WINBACK_INDEX, DWS_NEWCONV_INDEX, DWS_RELATION_INDEX) |
|
||||
| 建议 | 在 DWD 装载的日期类型转换中添加容错处理(捕获 ValueError,将非法日期置为 NULL 或哨兵值) |
|
||||
|
||||
---
|
||||
|
||||
## 修复文件清单
|
||||
|
||||
| 文件 | 修复的 BUG |
|
||||
|------|-----------|
|
||||
| `apps/etl/connectors/feiqiu/tasks/dws/assistant_daily_task.py` | BUG 1 |
|
||||
| `apps/etl/connectors/feiqiu/tasks/dws/assistant_monthly_task.py` | BUG 2 |
|
||||
| `apps/etl/connectors/feiqiu/tasks/dws/assistant_customer_task.py` | BUG 3, 4 |
|
||||
| `apps/etl/connectors/feiqiu/tasks/dws/member_consumption_task.py` | BUG 4 |
|
||||
| `apps/etl/connectors/feiqiu/tasks/dws/member_visit_task.py` | BUG 5, 6 |
|
||||
| `apps/etl/connectors/feiqiu/tasks/dws/finance_income_task.py` | BUG 7 |
|
||||
| `apps/etl/connectors/feiqiu/tasks/dws/finance_base_task.py` | BUG 8 |
|
||||
| `apps/etl/connectors/feiqiu/tasks/dws/finance_recharge_task.py` | BUG 4, 8 |
|
||||
| `apps/etl/connectors/feiqiu/tasks/dwd/dwd_load_task.py` | BUG 9, 10 |
|
||||
| `apps/etl/connectors/feiqiu/orchestration/flow_runner.py` | BUG 11 |
|
||||
|
||||
---
|
||||
|
||||
## 执行历史
|
||||
|
||||
| 版本 | execution_id | 耗时 | 成功 | 失败 | 修复验证 |
|
||||
|------|-------------|------|------|------|---------|
|
||||
| v1 | `dbf0c29a-...` | 590.7s | 10 | 31 | — |
|
||||
| v2 | `e21e1935-...` | 150.4s | — | — | BUG 1 ✅ |
|
||||
| v3 | `abc94b2d-...` | 681.2s | 9 | 22 | BUG 2,3 ✅ |
|
||||
| v4 | `efd4f421-...` | 11m55s | 10 | 21 | BUG 4 ✅ |
|
||||
| v5 | `fe87144a-...` | 11m37s | 10 | 21 | BUG 5 部署(被 BUG 6 遮蔽) |
|
||||
| v6 | `d9443781-...` | 29m26s | 11 | 8 | BUG 5,6,7 ✅ |
|
||||
| v7 | `0929ab3a-...` | 89.3s | — | 全部 | BUG 8 部署(被 BUG 9 遮蔽) |
|
||||
| v8 | `f943bac6-...` | 1m24s | 14 | 5 | BUG 8,9,10,11 ✅ |
|
||||
"""
|
||||
|
||||
(out / "2026-02-21__etl_full_bug_report.md").write_text(report, encoding="utf-8")
|
||||
print(f"报告已导出: {out / '2026-02-21__etl_full_bug_report.md'}")
|
||||
Reference in New Issue
Block a user