# 生成 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 CAUSE：DWS_MEMBER_CONSUMPTION 失败

**根因分析**：两个 BUG 叠加导致任务失败。

#### BUG-1：FDW 外部表未部署

- **现象**：查询 `fdw_app.member_birthday_manual` 时报错（外部表不存在）
- **原因**：`db/fdw/setup_fdw_reverse.sql` 中定义的反向 FDW 外部表未在测试库部署
- **影响**：主 SQL 执行失败，触发 rollback，进入 `sql_fallback` 分支

#### BUG-2：sql_fallback 列名错误

- **现象**：fallback SQL 引用了不存在的列 `tenant_member_id`
- **原因**：实际列名应为 `member_id`，fallback SQL 未与表结构同步
- **影响**：fallback 也失败，事务进入 `InFailedSqlTransaction` 状态

### 3.4 CASCADE FAILURE：10 个任务级联失败

- **触发点**：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}")
