Prefect 同步跳过缺失表并推送飞书提醒
This commit is contained in:
@@ -2,7 +2,7 @@ import json
|
||||
import os
|
||||
import re
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import date, datetime, timedelta, timezone
|
||||
from decimal import Decimal
|
||||
from pathlib import Path
|
||||
@@ -380,6 +380,17 @@ class MetricSyncArtifacts:
|
||||
created_fields: set[str]
|
||||
|
||||
|
||||
@dataclass(frozen=True, order=True)
|
||||
class MissingTable:
|
||||
project: str
|
||||
year: int
|
||||
month: int
|
||||
|
||||
|
||||
class TargetTableNotFoundError(ValueError):
|
||||
"""Raised when a project's monthly Feishu table does not exist."""
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class DailySyncConfig:
|
||||
base_url: str
|
||||
@@ -400,6 +411,7 @@ class DailySyncContext:
|
||||
mapping: dict[str, str]
|
||||
table_overrides: dict[str, str]
|
||||
config: DailySyncConfig
|
||||
missing_tables: set[MissingTable] = field(default_factory=set)
|
||||
|
||||
|
||||
def _log_to_prefect(level_name: str, message: str) -> None:
|
||||
@@ -938,6 +950,7 @@ def send_feishu_sync_card(
|
||||
base_url: str,
|
||||
start_date: date,
|
||||
end_date: date,
|
||||
extra_content: str = "",
|
||||
) -> None:
|
||||
if not webhook_url:
|
||||
log_step("未配置飞书群机器人 webhook,跳过群消息推送")
|
||||
@@ -958,6 +971,7 @@ def send_feishu_sync_card(
|
||||
"content": (
|
||||
f"**同步范围**\n{start_date.isoformat()} 至 {end_date.isoformat()}\n\n"
|
||||
f"**多维表格**\n[点击打开多维表格]({base_url})"
|
||||
+ (f"\n\n{extra_content}" if extra_content else "")
|
||||
),
|
||||
},
|
||||
}
|
||||
@@ -1005,6 +1019,7 @@ def send_feishu_app_card(
|
||||
end_date: date,
|
||||
image_path: str = "",
|
||||
token: str | None = None,
|
||||
extra_content: str = "",
|
||||
) -> None:
|
||||
if not chat_id:
|
||||
log_step("未配置 FEISHU_CHAT_ID,跳过应用机器人卡片推送")
|
||||
@@ -1019,6 +1034,7 @@ def send_feishu_app_card(
|
||||
"content": (
|
||||
f"**同步范围**\n{start_date.isoformat()} 至 {end_date.isoformat()}\n\n"
|
||||
f"**多维表格**\n[{title}]({base_url})"
|
||||
+ (f"\n\n{extra_content}" if extra_content else "")
|
||||
),
|
||||
},
|
||||
}
|
||||
@@ -1118,7 +1134,7 @@ def find_target_table(
|
||||
return candidates[0]
|
||||
if not candidates:
|
||||
all_table_names = [table.name for table in tables]
|
||||
raise ValueError(
|
||||
raise TargetTableNotFoundError(
|
||||
f"未找到匹配表: 项目={project}, 月份={year:04d}-{month:02d}, 项目相关表={project_related_tables or '[]'}, 全部表={all_table_names}"
|
||||
)
|
||||
raise ValueError(
|
||||
@@ -1715,8 +1731,15 @@ def run_daily_sync_for_date(context: DailySyncContext, stat_date: date) -> None:
|
||||
}
|
||||
try:
|
||||
table = find_target_table(context.tables, project, stat_date.year, stat_date.month, context.table_overrides)
|
||||
except ValueError as exc:
|
||||
except TargetTableNotFoundError as exc:
|
||||
if context.config.skip_missing_tables:
|
||||
missing_table = MissingTable(project=project, year=stat_date.year, month=stat_date.month)
|
||||
if missing_table not in context.missing_tables:
|
||||
context.missing_tables.add(missing_table)
|
||||
log_step(
|
||||
"记录缺失表: "
|
||||
f"项目={project}, 月份={stat_date.year:04d}-{stat_date.month:02d}"
|
||||
)
|
||||
log_step(f"跳过: {exc}")
|
||||
continue
|
||||
raise
|
||||
@@ -1815,3 +1838,43 @@ def send_sync_notification(
|
||||
start_date=start_date,
|
||||
end_date=end_date,
|
||||
)
|
||||
|
||||
|
||||
def send_missing_table_notification(
|
||||
context: DailySyncContext,
|
||||
missing_tables: set[MissingTable],
|
||||
start_date: date,
|
||||
end_date: date,
|
||||
) -> None:
|
||||
"""Notify Feishu once after a sync run about tables skipped because they do not exist."""
|
||||
if context.config.dry_run or not missing_tables:
|
||||
return
|
||||
|
||||
table_lines = "\n".join(
|
||||
f"- {item.project}:{item.year:04d}-{item.month:02d}" for item in sorted(missing_tables)
|
||||
)
|
||||
extra_content = (
|
||||
"**以下月份表不存在,已跳过写入**\n"
|
||||
f"{table_lines}\n\n"
|
||||
"请创建对应月份表后重新执行补数。"
|
||||
)
|
||||
title = "GMV 数据同步:缺失表提醒"
|
||||
if context.config.chat_id:
|
||||
send_feishu_app_card(
|
||||
chat_id=context.config.chat_id,
|
||||
title=title,
|
||||
base_url=context.config.base_url,
|
||||
start_date=start_date,
|
||||
end_date=end_date,
|
||||
token=context.client.token,
|
||||
extra_content=extra_content,
|
||||
)
|
||||
return
|
||||
send_feishu_sync_card(
|
||||
webhook_url=context.config.group_webhook,
|
||||
title=title,
|
||||
base_url=context.config.base_url,
|
||||
start_date=start_date,
|
||||
end_date=end_date,
|
||||
extra_content=extra_content,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user