Files
Neo-ZQYY/scripts/ops/gen_integration_report.py
Neo 2a7a5d68aa feat: 2026-04-15~04-20 累积变更基线 — 多主线合流
主线 1: rns1-customer-coach-api + 04-miniapp-core-business 后端实施
  - 新增 GET /xcx/coaches/{id}/banner 轻量接口
  - performance/records 加 coach_id 参数 + view_board_coach 权限分流
  - coach/customer/performance/board/task 服务层重构
  - fdw_queries 结算单粒度聚合 + consumption_summary 视图统一
  - task_generator 回访宽限 72h + UPSERT 替代策略 + Step 5 保底清理
  - recall_detector settle_type=3 双重限制 + 门店级 resolved

主线 2: 小程序权限分流 + 新增 coach-service-records 管理者视角业绩明细页
  - perf-progress 共享模块去重 task-list/coach-detail 动画逻辑
  - isScattered 散客标记端到端
  - foodDetail/phoneFull/creator* 字段透传

主线 3: P19 指数回测框架 Phase 1+2
  - 3 个指数表 stat_date 日快照模式
  - 新增 DWS_INDEX_BACKFILL / DWS_TASK_SIMULATION 工具任务
  - task_engine 升级 HTTP 实时 + 推演回测双模式

主线 4: Core 维度层启用
  - 新增 CORE_DIM_SYNC 任务(DWD → core 4 维度表)
  - 修复 app 视图空查询问题

主线 5: member_project_tag 改为 LAST_30_VISITS 消费次数窗口

主线 6: 2 个迁移 SQL 已执行(stat_date + member_project_tag 新窗口)
  - schema 基线与 DDL 快照同步

主线 7: 开发机路径迁移 C:\NeoZQYY → C:\Project\NeoZQYY(约 95% 改动量)

附带: 新建运维脚本(churned_customer_report / simulate_historical_tasks /
      backfill_index_snapshots)+ tools/task-analysis/ 任务分析工具

合计 157 文件。未包含中间产物(tmp/ .playwright-mcp/ inspect-* excel/sheet 分析 txt)。
审计记录见下一个 commit。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 06:32:07 +08:00

247 lines
8.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 生成 ETL 全流程联调综合报告
# 输出路径:{SYSTEM_LOG_ROOT}/{date}__etl_integration_report.md
# 环境变量 SYSTEM_LOG_ROOT 缺失时报错终止。
# 用法cd C:\Project\NeoZQYY && python scripts/ops/gen_integration_report.py
import os
import sys
from pathlib import Path
from dotenv import load_dotenv
# 加载根 .env
load_dotenv(Path(__file__).resolve().parents[2] / ".env")
SYSTEM_LOG_ROOT = os.environ.get("SYSTEM_LOG_ROOT")
if not SYSTEM_LOG_ROOT:
print("ERROR: 环境变量 SYSTEM_LOG_ROOT 未设置,无法输出报告。", file=sys.stderr)
sys.exit(1)
output_dir = Path(SYSTEM_LOG_ROOT)
output_dir.mkdir(parents=True, exist_ok=True)
REPORT_DATE = "2026-02-24"
output_path = output_dir / f"{REPORT_DATE}__etl_integration_report.md"
# ── 报告内容 ──────────────────────────────────────────────────────────────────
REPORT = r"""# ETL 全流程联调报告
> 生成时间2026-02-24
> execution_id: `41938155-db8c-4eec-9b81-9e5aef42fb8a`
> run_uuid: `f764a42487c34e0f9bd19e4fa9c57f03`
---
## 1. 执行概要
| 项目 | 值 |
|------|-----|
| Flow | `api_full`API → ODS → DWD → DWS → INDEX |
| 处理模式 | `full_window`(全窗口) |
| 时间窗口 | 2025-11-01 ~ 2026-02-20自定义 |
| 窗口切分 | 30 天/切片,共 4 个切片 |
| force_full | 是 |
| 任务数 | 41 个常用任务(`is_common=True` |
| 开始时间 | 2026-02-24 12:27:22 |
| 结束时间 | 2026-02-24 13:05:43 |
| 总耗时 | 38m22s |
| 退出码 | 0 |
| 最终状态 | **success** |
| 数据统计 | 225,760 fetched / 13,437 inserted / 225,648 updated |
### 窗口切片
| 切片 | 窗口范围 |
|------|---------|
| 1 | 2025-10-31 22:00 ~ 2025-11-30 22:00 |
| 2 | 2025-11-30 22:00 ~ 2025-12-30 22:00 |
| 3 | 2025-12-30 22:00 ~ 2026-01-29 22:00 |
| 4 | 2026-01-29 22:00 ~ 2026-02-20 02:00 |
---
## 2. 性能报告
### 2.1 阶段耗时汇总
| 阶段 | 墙钟耗时 | 占比 | 状态 |
|------|---------|------|------|
| ODS | 31m17s | 81.8% | ✅ 全部成功21 任务 + 1 跳过) |
| DWD | 2m30s | 6.5% | ✅ 全部成功1 任务) |
| DWS | 4m29s | 11.7% | ⚠️ 7 成功 / 8 失败 |
| INDEX | <1s | 0.0% | ❌ 3 任务全部失败(级联) |
| **合计** | **38m16s** | **100%** | 29 成功 / 11 失败 / 1 跳过 |
### 2.2 Top-5 耗时瓶颈
| 排名 | 任务 | 阶段 | 耗时 | 备注 |
|------|------|------|------|------|
| 1 | ODS_PLATFORM_COUPON | ODS | 10m41s | 数据量大4 切片均 >2m |
| 2 | ODS_TABLE_USE | ODS | 4m23s | 每切片 ~1m |
| 3 | ODS_GROUP_BUY_REDEMPTION | ODS | 4m22s | 每切片 ~1m |
| 4 | ODS_PAYMENT | ODS | 4m7s | 每切片 ~1m |
| 5 | DWS_ASSISTANT_DAILY | DWS | 2m43s | 聚合计算密集 |
> Top-5 合计 26m16s占总耗时 68.6%。ODS 阶段 API 拉取是主要瓶颈。
### 2.3 ODS 任务耗时明细
| 任务 | 切片数 | 总耗时 | 状态 |
|------|--------|--------|------|
| ODS_PLATFORM_COUPON | 4 | 10m41s | ✅ |
| ODS_TABLE_USE | 4 | 4m23s | ✅ |
| ODS_GROUP_BUY_REDEMPTION | 4 | 4m22s | ✅ |
| ODS_PAYMENT | 4 | 4m7s | ✅ |
| ODS_MEMBER_BALANCE | 4 | 2m8s | ✅ |
| ODS_SETTLEMENT_RECORDS | 4 | 1m45s | ✅ |
| ODS_TABLE_FEE_DISCOUNT | 4 | 54s | ✅ |
| ODS_INVENTORY_CHANGE | 4 | 48s | ✅ |
| ODS_MEMBER_CARD | 4 | 35s | ✅ |
| ODS_ASSISTANT_LEDGER | 4 | 24s | ✅ |
| ODS_MEMBER | 4 | 14s | ✅ |
| ODS_INVENTORY_STOCK | 4 | 9s | ✅ |
| ODS_ASSISTANT_ACCOUNT | 4 | 7s | ✅ |
| ODS_STORE_GOODS | 4 | 7s | ✅ |
| ODS_REFUND | 4 | 4s | ✅ |
| ODS_RECHARGE_SETTLE | 4 | 4s | ✅ |
| ODS_TENANT_GOODS | 4 | 4s | ✅ |
| ODS_TABLES | 4 | 2s | ✅ |
| ODS_GROUP_PACKAGE | 4 | 2s | ✅ |
| ODS_GOODS_CATEGORY | 4 | 1s | ✅ |
| ODS_STORE_GOODS_SALES | 4 | 1s | ✅ |
### 2.4 DWD 任务耗时明细
| 任务 | 切片数 | 总耗时 | 状态 |
|------|--------|--------|------|
| DWD_LOAD_FROM_ODS | 4 | 2m30s | ✅ |
### 2.5 DWS 任务耗时明细
| 任务 | 切片数 | 总耗时 | 状态 |
|------|--------|--------|------|
| DWS_ASSISTANT_DAILY | 4 | 2m43s | ✅ |
| DWS_ASSISTANT_CUSTOMER | 4 | 1m32s | ✅ |
| DWS_GOODS_STOCK_MONTHLY | 4 | 1s | ✅ |
| DWS_BUILD_ORDER_SUMMARY | 0 | 1s | ✅ |
| DWS_GOODS_STOCK_DAILY | 4 | <1s | ✅ |
| DWS_GOODS_STOCK_WEEKLY | 4 | <1s | ✅ |
| DWS_ASSISTANT_SALARY | 4 | <1s | ✅ |
| DWS_MEMBER_CONSUMPTION | — | — | ❌ 失败(根因) |
| DWS_MEMBER_VISIT | — | — | ❌ 级联失败 |
| DWS_FINANCE_DAILY | — | — | ❌ 级联失败 |
| DWS_FINANCE_RECHARGE | — | — | ❌ 级联失败 |
| DWS_FINANCE_INCOME_STRUCTURE | — | — | ❌ 级联失败 |
| DWS_FINANCE_DISCOUNT_DETAIL | — | — | ❌ 级联失败 |
| DWS_ASSISTANT_MONTHLY | — | — | ❌ 级联失败 |
| DWS_ASSISTANT_FINANCE | — | — | ❌ 级联失败 |
### 2.6 INDEX 任务耗时明细
| 任务 | 状态 |
|------|------|
| DWS_WINBACK_INDEX | ❌ 级联失败 |
| DWS_NEWCONV_INDEX | ❌ 级联失败 |
| DWS_RELATION_INDEX | ❌ 级联失败 |
---
## 3. DEBUG 报告
### 3.1 错误摘要
共发现 **1 个根因错误**,导致 **10 个任务级联失败**。
### 3.2 ROOT CAUSEDWS_MEMBER_CONSUMPTION 失败
**根因分析**:两个 BUG 叠加导致任务失败。
#### BUG-1FDW 外部表未部署
- **现象**:查询 `fdw_app.member_birthday_manual` 时报错(外部表不存在)
- **原因**`db/fdw/setup_fdw_reverse.sql` 中定义的反向 FDW 外部表未在测试库部署
- **影响**:主 SQL 执行失败,触发 rollback进入 `sql_fallback` 分支
#### BUG-2sql_fallback 列名错误
- **现象**fallback SQL 引用了不存在的列 `tenant_member_id`
- **原因**:实际列名应为 `member_id`fallback SQL 未与表结构同步
- **影响**fallback 也失败,事务进入 `InFailedSqlTransaction` 状态
### 3.4 CASCADE FAILURE10 个任务级联失败
- **触发点**DWS_MEMBER_CONSUMPTION 失败后,数据库连接的事务处于 `InFailedSqlTransaction` 状态
- **根因**`run_tasks` 的 `except` 块未调用 `self.db.rollback()`,导致后续所有任务在同一个已失败的事务中执行
- **级联任务**(共 10 个):
1. DWS_MEMBER_VISIT
2. DWS_FINANCE_DAILY
3. DWS_FINANCE_RECHARGE
4. DWS_FINANCE_INCOME_STRUCTURE
5. DWS_FINANCE_DISCOUNT_DETAIL
6. DWS_ASSISTANT_MONTHLY
7. DWS_ASSISTANT_FINANCE
8. DWS_WINBACK_INDEX
9. DWS_NEWCONV_INDEX
10. DWS_RELATION_INDEX
### 3.5 修复建议
| 优先级 | 修复项 | 说明 |
|--------|--------|------|
| **P0** | 修复 SQL 列名 | `tenant_member_id` → `member_id`DWS_MEMBER_CONSUMPTION 的 sql_fallback |
| **P0** | run_tasks except 块添加 rollback | `self.db.rollback()` 防止级联失败 |
| **P1** | 部署 FDW 外部表 | 执行 `db/fdw/setup_fdw_reverse.sql` 到测试库 |
---
## 4. 黑盒测试报告
> ⏳ 待补充 — 将在 Task 5.3 完成后追加。
>
> 预期内容:
> - API vs ODS通过数/总数
> - ODS vs DWD通过数/总数
> - DWD vs DWS表概览
> - 白名单差异统计
> - 失败表清单
> - 全链路检查报告路径引用
---
## 附录
### A. 完整 CLI 参数
```
--flow api_full
--processing-mode full_window
--window-start 2025-11-01
--window-end 2026-02-20
--window-split day
--window-split-days 30
--force-full
--tasks ODS_ASSISTANT_ACCOUNT ODS_ASSISTANT_LEDGER
ODS_SETTLEMENT_RECORDS ODS_TABLE_USE ODS_TABLE_FEE_DISCOUNT
ODS_TABLES ODS_PAYMENT ODS_REFUND ODS_PLATFORM_COUPON
ODS_MEMBER ODS_MEMBER_CARD ODS_MEMBER_BALANCE ODS_RECHARGE_SETTLE
ODS_GROUP_PACKAGE ODS_GROUP_BUY_REDEMPTION
ODS_INVENTORY_STOCK ODS_INVENTORY_CHANGE
ODS_GOODS_CATEGORY ODS_STORE_GOODS ODS_STORE_GOODS_SALES ODS_TENANT_GOODS
DWD_LOAD_FROM_ODS
DWS_BUILD_ORDER_SUMMARY DWS_ASSISTANT_DAILY DWS_ASSISTANT_MONTHLY
DWS_ASSISTANT_CUSTOMER DWS_ASSISTANT_SALARY DWS_ASSISTANT_FINANCE
DWS_MEMBER_CONSUMPTION DWS_MEMBER_VISIT
DWS_FINANCE_DAILY DWS_FINANCE_RECHARGE DWS_FINANCE_INCOME_STRUCTURE
DWS_FINANCE_DISCOUNT_DETAIL
DWS_GOODS_STOCK_DAILY DWS_GOODS_STOCK_WEEKLY DWS_GOODS_STOCK_MONTHLY
DWS_WINBACK_INDEX DWS_NEWCONV_INDEX DWS_RELATION_INDEX
```
### B. 精细计时报告
完整的窗口切片级计时数据见:`export/temp_timing_report.md`
"""
output_path.write_text(REPORT.strip(), encoding="utf-8")
print(f"✅ 报告已生成: {output_path}")