'日志系统迭代'
This commit is contained in:
parent
403b8fee0d
commit
c5f2c64e82
@ -9,16 +9,16 @@ workspace_id = 58335167
|
||||
# 支持配置多个docid,用逗号分隔,例如:
|
||||
# docid = doc1,doc2,doc3
|
||||
# 同步时会依次对所有表格进行同步
|
||||
docid = dcOsT3czWy0YEDg38vlDqwVCTjv0kzwC_GU2XmT9wSZctQ0ZJQUAV7vMQ3ljZx-n_NqxzEEYG2DiLAvNdNsHJwgQ,dcHWzWyaHpZNQwUkZzgH5Kfyx9cMvQzVjZIapajGDuXqjS4nEe0LQqOojBL8s3rlwghw4deOgVnbOqHLoxcKzaHg
|
||||
#docid =dc2Q5Kb0T4zerbo4_ag0MMcXHCusIaFJX5fO6_8n-l_yV-bn5brZSi1kNw3kjme-qIs0LvPKbC5GDEEPaZ1BGlvA
|
||||
# docid = dcOsT3czWy0YEDg38vlDqwVCTjv0kzwC_GU2XmT9wSZctQ0ZJQUAV7vMQ3ljZx-n_NqxzEEYG2DiLAvNdNsHJwgQ,dcHWzWyaHpZNQwUkZzgH5Kfyx9cMvQzVjZIapajGDuXqjS4nEe0LQqOojBL8s3rlwghw4deOgVnbOqHLoxcKzaHg
|
||||
docid =dc2Q5Kb0T4zerbo4_ag0MMcXHCusIaFJX5fO6_8n-l_yV-bn5brZSi1kNw3kjme-qIs0LvPKbC5GDEEPaZ1BGlvA
|
||||
|
||||
[Schedule]
|
||||
# 同步频率(分钟)
|
||||
sync_interval = 30
|
||||
sync_interval = 1
|
||||
|
||||
[wework]
|
||||
# 企业微信应用ID
|
||||
agentid = 1000615
|
||||
# 接收人列表(用户ID,多个用|分隔,@all表示全部成员)
|
||||
# receivers = 046364
|
||||
receivers = 040005
|
||||
receivers = 046364
|
||||
# receivers = 114514
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
{
|
||||
"access_token": "GQKX61Nh9c5A4Mp0FDOGy4nZgnFok2gefTA0_X4Y5PEL7NkpD9UHWwji3lWkZLsHMJf3dpbJ_l-NdichZ5qSZuPhF7kJNU47Blf2yLQRqFctmXMU6m1cWU80iLiY0vrX2EPzvldaHMR-al3HgKK6PUSU9T2a5Xp-lCjh9StPzEnQJUnwickV4PiPegLLGcH5F6jcM-9pHztkJ6pSV6bfP5QFFATAldmj-71Occib9V0",
|
||||
"fetch_time": 1772269143.6670134
|
||||
"access_token": "720bS457oj9c3NehV8Be0YZoqDTdzQhlk1MppoMMdn078G_ZDiJ5BPzbLw5nckIpV6rQLGBYeNc-GkKJgFNMKbhqa52JUDj6o0czz3q3WGAVGEH4z-GSSPDrHft38yjG_kjnk1Aa_LayL6dG_Ndy8POYhNKxyjiAz_veePxnzpWzhwRrQA5YsL2ufrAD12sjL6zfBONkDrLweLjlXPWVK3J9VJThtBMN0K3xzFI0Ku0",
|
||||
"fetch_time": 1773146433.440257
|
||||
}
|
||||
@ -54,20 +54,20 @@
|
||||
- **接口(对内)**:`create_bug`、`get_bug`、`upload_attachment` 等。
|
||||
- `src/token_manager.py`
|
||||
- **职责**:企业微信 `access_token` 获取与缓存。
|
||||
- **接口(对内)**:`get_token()`。
|
||||
- **接口(对内)**:`__init__(cache_file_path=None, logger=None)`、`get_token()`。
|
||||
- `src/wework_notifier.py`
|
||||
- **职责**:企业微信消息通知。
|
||||
- **接口(对内)**:`send_validation_failure_notification(...)`。
|
||||
- **接口(对内)**:`__init__(access_token, agentid, receivers, logger=None)`、`send_validation_failure_notification(...)`。
|
||||
- `src/api_logger.py`
|
||||
- **职责**:现有日志记录器(后续将作为兼容层)。
|
||||
|
||||
## 2.2 任务二(`src2/`)
|
||||
- `src2/scheduler.py`
|
||||
- **职责**:任务二调度入口,定时触发同步。
|
||||
- **职责**:任务二调度入口,定时触发同步并记录每次同步边界与统计。
|
||||
- **关键依赖**:`src2/sync_service.py`。
|
||||
- `src2/sync_service.py`
|
||||
- **职责**:任务二同步编排(读取、解析链接、查询 TAPD、回写、通知)。
|
||||
- **接口(对内)**:`sync_once()`。
|
||||
- **接口(对内)**:`sync_once()`、`run_once(...)`(无外层同步时自动兜底边界)。
|
||||
- `src2/smartsheet.py`
|
||||
- **职责**:任务二智能表格 API 适配层。
|
||||
- **关键点**:应固定写入 `logs2/`。
|
||||
@ -76,18 +76,18 @@
|
||||
- `src2/tapd_api.py`
|
||||
- **职责**:任务二 TAPD Story 查询与状态映射。
|
||||
- `src2/notifier.py`
|
||||
- **职责**:任务二失败通知封装(当前复用任务一通知器,存在串目录风险)。
|
||||
- **职责**:任务二失败通知封装(复用任务一通知器并显式注入任务二 logger,避免串目录)。
|
||||
- `src2/logger.py`
|
||||
- **职责**:任务二日志实例入口(后续接入统一内核)。
|
||||
- **职责**:任务二日志实例入口(固定写入 `logs2/`,接入统一内核兼容层)。
|
||||
|
||||
---
|
||||
|
||||
## 3. 现存问题与待改造点
|
||||
## 3. 现存问题与待改造点(阶段3后)
|
||||
|
||||
- **串目录问题**:任务二复用 `TokenManager`、`WeWorkNotifier` 可能写入 `logs/`。
|
||||
- **双记录矛盾**:同一次请求在部分分支可能出现先成功后失败两条记录。
|
||||
- **写入稳定性问题**:现有按 JSON 数组拼接的策略会造成结构损坏风险。
|
||||
- **同步边界缺失**:缺少标准化 `start_sync` / `end_sync` 分隔与统计记录。
|
||||
- **串目录问题(生产链路)**:已修复,`src2` 生产入口统一显式注入任务二 logger。
|
||||
- **双记录矛盾(任务一)**:已修复;任务二当前未发现同请求双写路径。
|
||||
- **写入稳定性问题**:已由统一 `jsonl` 事件流替代旧数组拼接策略。
|
||||
- **阶段4待办**:日志查看工具尚未完成 `jsonl + sync_id` 体验优化。
|
||||
|
||||
---
|
||||
|
||||
@ -95,7 +95,7 @@
|
||||
|
||||
- 阶段1:新增全局日志内核模块,定义统一接口。(已完成)
|
||||
- 阶段2:`src/api_logger.py` 改造成兼容层,保证旧调用可用。(已完成)
|
||||
- 阶段3:`src2/logger.py` 与任务二编排层切换到统一内核,修复串目录。
|
||||
- 阶段3:`src2/logger.py` 与任务二编排层切换到统一内核,修复串目录。(已完成)
|
||||
- 阶段4:更新查看工具与文档,支持 `jsonl + sync_id`。
|
||||
|
||||
---
|
||||
@ -115,3 +115,8 @@
|
||||
- `src/scheduler.py` 的 `job/sync_job` 已接入同步边界与统计事件。
|
||||
- `src/main.py` 的 `run_once` 已接入手动兜底同步边界。
|
||||
- `src/smartsheet.py` 已消除同请求双记录矛盾。
|
||||
|
||||
### 2026-03-10(更新3)
|
||||
- 标记阶段3完成:任务二生产链路已接入同步边界与统计收尾。
|
||||
- TokenManager、WeWorkNotifier 已支持 logger 注入,用于任务二目录隔离。
|
||||
- src2/notifier.py、src2/sync_service.py、src2/main.py、src2/scheduler.py 已完成 logs2 链路闭环。
|
||||
|
||||
@ -143,3 +143,46 @@
|
||||
- **可回滚点**:可按文件粒度回滚(`src/api_logger.py` 与 `src/scheduler.py` 为关键点)。
|
||||
- **关联文档**:`docs/日志系统重构实施方案.md`
|
||||
- **备注**:下一阶段优先处理任务二串目录与通知链路复用问题。
|
||||
|
||||
## 阶段3:接入任务二(src2)
|
||||
- **阶段名称**:日志系统重构 - 阶段3
|
||||
- **日期**:2026-03-10
|
||||
- **负责人**:Codex
|
||||
- **目标**:修复任务二串目录问题,补齐任务二同步分隔与统计收尾,确保生产链路日志只落 `logs2/`。
|
||||
|
||||
### 变更清单
|
||||
- **新增文件**:无
|
||||
- **修改文件**:
|
||||
- `src/token_manager.py`
|
||||
- `src/wework_notifier.py`
|
||||
- `src2/scheduler.py`
|
||||
- `src2/main.py`
|
||||
- `src2/sync_service.py`
|
||||
- `src2/notifier.py`
|
||||
- `docs/全局迭代日志.md`
|
||||
- `docs/全局框架文档.md`
|
||||
- **删除文件**:无
|
||||
|
||||
### 关键改动说明
|
||||
- **日志结构变更**:任务二调度链路与手动入口均补齐 `start_sync/end_sync_with_stats`,按 `sync_id` 分隔并写入统计。
|
||||
- **接口/调用链变更**:
|
||||
- `TokenManager` 与 `WeWorkNotifier` 新增可选 `logger` 注入参数。
|
||||
- `src2/scheduler.py`、`src2/main.py`、`src2/sync_service.py` 全部接入任务二 logger 边界控制。
|
||||
- `src2/notifier.py` 调用通知器时显式注入 `get_task2_logger()`。
|
||||
- **兼容性说明**:旧调用不传 `logger` 仍保持任务一默认行为,生产链路通过显式注入实现目录隔离。
|
||||
|
||||
### 验收结果
|
||||
- **通过项**:
|
||||
- 任务二生产链路(`src2/scheduler.py`)已具备每次同步开始/结束事件与统计写入。
|
||||
- 任务二手动入口(`src2/main.py`)与 `run_once` 兜底路径已具备同步边界。
|
||||
- 任务二 token 获取、通知链路、sync_service 自动取 token 全部使用任务二 logger,不再串写 `logs/`。
|
||||
- `api_type` 已明确映射为 `smartsheet/tapd/wework` 三类语义。
|
||||
- **未通过项**:
|
||||
- 未执行运行态联调(仅完成静态改造与代码级复核)。
|
||||
- **遗留风险**:
|
||||
- `src2/test_*` 中仍有 `TokenManager()` 默认实例,属于测试路径,不影响生产链路。
|
||||
|
||||
### 回滚与追踪
|
||||
- **可回滚点**:可按文件粒度回滚,优先关注 `src2/scheduler.py`、`src2/main.py`、`src2/sync_service.py`。
|
||||
- **关联文档**:`docs/日志系统重构实施方案.md`
|
||||
- **备注**:阶段4建议优先补日志查看工具对 `jsonl + sync_id` 的检索能力。
|
||||
|
||||
@ -26,12 +26,13 @@ class TokenManager:
|
||||
# 提前刷新时间(秒),在token过期前5分钟就刷新
|
||||
REFRESH_BEFORE_EXPIRE = 300
|
||||
|
||||
def __init__(self, cache_file_path: Optional[str] = None):
|
||||
def __init__(self, cache_file_path: Optional[str] = None, logger=None):
|
||||
"""
|
||||
初始化Token管理器
|
||||
|
||||
Args:
|
||||
cache_file_path: token缓存文件路径,如果为None则使用默认路径
|
||||
logger: 可选日志实例,不传则使用默认任务一日志器
|
||||
"""
|
||||
# 确定缓存文件路径
|
||||
if cache_file_path is None:
|
||||
@ -46,7 +47,7 @@ class TokenManager:
|
||||
self.corpsecret = os.environ.get('CORPSECRET')
|
||||
|
||||
# 初始化日志记录器
|
||||
self.logger = get_logger()
|
||||
self.logger = logger if logger is not None else get_logger()
|
||||
|
||||
def _validate_env_config(self):
|
||||
"""
|
||||
|
||||
@ -14,7 +14,7 @@ from src.api_logger import get_logger
|
||||
class WeWorkNotifier:
|
||||
"""企业微信消息推送类"""
|
||||
|
||||
def __init__(self, access_token: str, agentid: str, receivers: str):
|
||||
def __init__(self, access_token: str, agentid: str, receivers: str, logger=None):
|
||||
"""
|
||||
初始化企业微信消息推送器
|
||||
|
||||
@ -22,12 +22,13 @@ class WeWorkNotifier:
|
||||
access_token: 企业微信access_token
|
||||
agentid: 应用ID
|
||||
receivers: 接收人列表(用户ID,多个用|分隔,@all表示全部成员)
|
||||
logger: 可选日志实例,不传则使用默认任务一日志器
|
||||
"""
|
||||
self.access_token = access_token
|
||||
self.agentid = agentid
|
||||
self.receivers = receivers
|
||||
self.base_url = "https://qyapi.weixin.qq.com/cgi-bin"
|
||||
self.logger = get_logger()
|
||||
self.logger = logger if logger is not None else get_logger()
|
||||
|
||||
def send_validation_failure_notification(self, invalid_records: List[Dict]) -> bool:
|
||||
"""
|
||||
|
||||
51
src2/main.py
51
src2/main.py
@ -20,6 +20,7 @@ sys.path.insert(0, str(project_root))
|
||||
from src.token_manager import TokenManager
|
||||
from src2.config import Task2ConfigManager
|
||||
from src2.sync_service import run_once
|
||||
from src2.logger import get_task2_logger
|
||||
|
||||
|
||||
def parse_arguments():
|
||||
@ -110,10 +111,22 @@ def main():
|
||||
print(f"执行时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
||||
print("=" * 60)
|
||||
|
||||
logger = None
|
||||
|
||||
try:
|
||||
# 解析命令行参数
|
||||
args = parse_arguments()
|
||||
|
||||
logger = get_task2_logger()
|
||||
logger.start_sync(
|
||||
trigger="task2_main_manual",
|
||||
metadata={
|
||||
"entry": "src2/main.py:main",
|
||||
"test_mode": args.test,
|
||||
"manual_token": bool(args.token),
|
||||
},
|
||||
)
|
||||
|
||||
# 初始化配置管理器
|
||||
print("\n正在加载配置...")
|
||||
config_manager = Task2ConfigManager(config_path=args.config)
|
||||
@ -123,7 +136,7 @@ def main():
|
||||
access_token = args.token
|
||||
if access_token is None:
|
||||
print("正在获取access_token...")
|
||||
token_manager = TokenManager()
|
||||
token_manager = TokenManager(logger=logger)
|
||||
access_token = token_manager.get_token()
|
||||
print(f" ✓ access_token获取成功")
|
||||
|
||||
@ -138,19 +151,53 @@ def main():
|
||||
# 打印结果摘要
|
||||
print_result_summary(result)
|
||||
|
||||
logger.end_sync_with_stats(
|
||||
stats={
|
||||
"docs_total": result.get("docs_total", 0),
|
||||
"docs_success": result.get("docs_success", 0),
|
||||
"docs_failed": result.get("docs_failed", 0),
|
||||
"sheets_processed": result.get("sheets_processed", 0),
|
||||
"sheets_skipped": result.get("sheets_skipped", 0),
|
||||
"total_records": result.get("total_records", 0),
|
||||
"records_with_link": result.get("records_with_link", 0),
|
||||
"records_synced": result.get("records_synced", 0),
|
||||
"records_updated": result.get("records_updated", 0),
|
||||
"records_failed": result.get("records_failed", 0),
|
||||
},
|
||||
success=result.get("success", False),
|
||||
error_message=result.get("error_message"),
|
||||
extra={"source": "task2_main_manual"},
|
||||
)
|
||||
|
||||
# 返回状态码
|
||||
return 0 if result["success"] else 1
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("\n\n用户中断执行")
|
||||
if logger and logger.get_active_sync_id():
|
||||
logger.end_sync_with_stats(
|
||||
stats={},
|
||||
success=False,
|
||||
error_message="KeyboardInterrupt",
|
||||
extra={"source": "task2_main_manual"},
|
||||
)
|
||||
return 130
|
||||
|
||||
except Exception as e:
|
||||
print(f"\n✗ 执行失败: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
if logger and logger.get_active_sync_id():
|
||||
logger.end_sync_with_stats(
|
||||
stats={},
|
||||
success=False,
|
||||
error_message=str(e),
|
||||
extra={
|
||||
"source": "task2_main_manual",
|
||||
"exception_type": type(e).__name__,
|
||||
},
|
||||
)
|
||||
return 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
|
||||
@ -13,6 +13,7 @@ project_root = Path(__file__).parent.parent
|
||||
sys.path.insert(0, str(project_root))
|
||||
|
||||
from src.wework_notifier import WeWorkNotifier
|
||||
from src2.logger import get_task2_logger
|
||||
|
||||
|
||||
def send_sync_failure_notification(access_token: str, agentid: str,
|
||||
@ -40,7 +41,7 @@ def send_sync_failure_notification(access_token: str, agentid: str,
|
||||
content = _build_sync_failure_message(failed_records)
|
||||
|
||||
# 使用任务一的推送器发送消息
|
||||
notifier = WeWorkNotifier(access_token, agentid, receivers)
|
||||
notifier = WeWorkNotifier(access_token, agentid, receivers, logger=get_task2_logger())
|
||||
return notifier._send_text_message(content)
|
||||
|
||||
|
||||
|
||||
@ -30,6 +30,7 @@ except ImportError:
|
||||
from src.token_manager import TokenManager
|
||||
from src2.config import Task2ConfigManager
|
||||
from src2.sync_service import run_once
|
||||
from src2.logger import get_task2_logger
|
||||
|
||||
|
||||
class Task2Scheduler:
|
||||
@ -82,7 +83,7 @@ class Task2Scheduler:
|
||||
"""初始化TokenManager"""
|
||||
try:
|
||||
print("正在初始化TokenManager...")
|
||||
self.token_manager = TokenManager()
|
||||
self.token_manager = TokenManager(logger=get_task2_logger())
|
||||
print("✓ TokenManager初始化成功")
|
||||
except Exception as e:
|
||||
print(f"✗ TokenManager初始化失败: {e}")
|
||||
@ -90,6 +91,30 @@ class Task2Scheduler:
|
||||
|
||||
def job(self):
|
||||
"""执行一次同步任务"""
|
||||
logger = get_task2_logger()
|
||||
logger.start_sync(
|
||||
trigger="task2_scheduler_job",
|
||||
metadata={
|
||||
"entry": "src2/scheduler.py:Task2Scheduler.job",
|
||||
"verbose": self.verbose,
|
||||
}
|
||||
)
|
||||
|
||||
result = {
|
||||
"success": False,
|
||||
"docs_total": 0,
|
||||
"docs_success": 0,
|
||||
"docs_failed": 0,
|
||||
"sheets_processed": 0,
|
||||
"sheets_skipped": 0,
|
||||
"total_records": 0,
|
||||
"records_with_link": 0,
|
||||
"records_synced": 0,
|
||||
"records_updated": 0,
|
||||
"records_failed": 0,
|
||||
"error_message": None,
|
||||
}
|
||||
|
||||
print("\n" + "=" * 80)
|
||||
print(f"开始执行同步任务 - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
||||
print("=" * 80)
|
||||
@ -130,6 +155,24 @@ class Task2Scheduler:
|
||||
print(f" 错误信息: {result.get('error_message', '未知错误')}")
|
||||
print("-" * 80)
|
||||
|
||||
logger.end_sync_with_stats(
|
||||
stats={
|
||||
"docs_total": result.get("docs_total", 0),
|
||||
"docs_success": result.get("docs_success", 0),
|
||||
"docs_failed": result.get("docs_failed", 0),
|
||||
"sheets_processed": result.get("sheets_processed", 0),
|
||||
"sheets_skipped": result.get("sheets_skipped", 0),
|
||||
"total_records": result.get("total_records", 0),
|
||||
"records_with_link": result.get("records_with_link", 0),
|
||||
"records_synced": result.get("records_synced", 0),
|
||||
"records_updated": result.get("records_updated", 0),
|
||||
"records_failed": result.get("records_failed", 0),
|
||||
},
|
||||
success=result.get("success", False),
|
||||
error_message=result.get("error_message"),
|
||||
extra={"source": "task2_scheduler_job"},
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
self.stats['total_runs'] += 1
|
||||
self.stats['failed_runs'] += 1
|
||||
@ -146,6 +189,28 @@ class Task2Scheduler:
|
||||
print("\n详细错误信息:")
|
||||
traceback.print_exc()
|
||||
|
||||
if logger.get_active_sync_id():
|
||||
logger.end_sync_with_stats(
|
||||
stats={
|
||||
"docs_total": result.get("docs_total", 0),
|
||||
"docs_success": result.get("docs_success", 0),
|
||||
"docs_failed": result.get("docs_failed", 0),
|
||||
"sheets_processed": result.get("sheets_processed", 0),
|
||||
"sheets_skipped": result.get("sheets_skipped", 0),
|
||||
"total_records": result.get("total_records", 0),
|
||||
"records_with_link": result.get("records_with_link", 0),
|
||||
"records_synced": result.get("records_synced", 0),
|
||||
"records_updated": result.get("records_updated", 0),
|
||||
"records_failed": result.get("records_failed", 0),
|
||||
},
|
||||
success=False,
|
||||
error_message=str(e),
|
||||
extra={
|
||||
"source": "task2_scheduler_job",
|
||||
"exception_type": type(e).__name__,
|
||||
},
|
||||
)
|
||||
|
||||
# 显示下次执行时间
|
||||
self._show_next_run_time()
|
||||
|
||||
|
||||
@ -66,7 +66,7 @@ class SyncService:
|
||||
|
||||
# 获取access_token
|
||||
if access_token is None:
|
||||
token_manager = TokenManager()
|
||||
token_manager = TokenManager(logger=self.logger)
|
||||
self.access_token = token_manager.get_token()
|
||||
else:
|
||||
self.access_token = access_token
|
||||
@ -465,7 +465,7 @@ class SyncService:
|
||||
record_result["sync_status"] = "❌ 单号无效"
|
||||
# 记录链接解析失败日志
|
||||
self.logger.log_api_call(
|
||||
api_type="task2",
|
||||
api_type="smartsheet",
|
||||
operation="link_parse_failure",
|
||||
request_data={
|
||||
"record_id": record_info["record_id"],
|
||||
@ -526,7 +526,7 @@ class SyncService:
|
||||
record_result["sync_status"] = "❌ 单号无效"
|
||||
# 记录TAPD查询失败日志
|
||||
self.logger.log_api_call(
|
||||
api_type="task2",
|
||||
api_type="tapd",
|
||||
operation="sync_record_failure",
|
||||
request_data={
|
||||
"record_id": record_info["record_id"],
|
||||
@ -543,7 +543,7 @@ class SyncService:
|
||||
record_result["sync_status"] = "⚠️ 同步失败,请联系PM"
|
||||
# 记录TAPD查询失败日志
|
||||
self.logger.log_api_call(
|
||||
api_type="task2",
|
||||
api_type="tapd",
|
||||
operation="sync_record_failure",
|
||||
request_data={
|
||||
"record_id": record_info["record_id"],
|
||||
@ -685,7 +685,7 @@ class SyncService:
|
||||
error_msg = str(e)
|
||||
# 记录持续同步失败日志
|
||||
self.logger.log_api_call(
|
||||
api_type="task2",
|
||||
api_type="tapd",
|
||||
operation="continuous_sync_failure",
|
||||
request_data={
|
||||
"record_id": record_info["record_id"],
|
||||
@ -731,7 +731,7 @@ class SyncService:
|
||||
|
||||
# 记录到日志文件
|
||||
self.logger.log_api_call(
|
||||
api_type="task2",
|
||||
api_type="tapd",
|
||||
operation="cache_statistics",
|
||||
request_data={},
|
||||
response_data=stats,
|
||||
@ -803,8 +803,52 @@ def run_once(config_manager: Task2ConfigManager = None,
|
||||
access_token=access_token,
|
||||
test_mode=test_mode
|
||||
)
|
||||
return service.sync_once()
|
||||
|
||||
logger = service.logger
|
||||
started_sync_here = False
|
||||
if not logger.get_active_sync_id():
|
||||
logger.start_sync(
|
||||
trigger="task2_run_once_manual",
|
||||
metadata={
|
||||
"entry": "src2/sync_service.py:run_once",
|
||||
"test_mode": test_mode,
|
||||
},
|
||||
)
|
||||
started_sync_here = True
|
||||
|
||||
try:
|
||||
result = service.sync_once()
|
||||
if started_sync_here:
|
||||
logger.end_sync_with_stats(
|
||||
stats={
|
||||
"docs_total": result.get("docs_total", 0),
|
||||
"docs_success": result.get("docs_success", 0),
|
||||
"docs_failed": result.get("docs_failed", 0),
|
||||
"sheets_processed": result.get("sheets_processed", 0),
|
||||
"sheets_skipped": result.get("sheets_skipped", 0),
|
||||
"total_records": result.get("total_records", 0),
|
||||
"records_with_link": result.get("records_with_link", 0),
|
||||
"records_synced": result.get("records_synced", 0),
|
||||
"records_updated": result.get("records_updated", 0),
|
||||
"records_failed": result.get("records_failed", 0),
|
||||
},
|
||||
success=result.get("success", False),
|
||||
error_message=result.get("error_message"),
|
||||
extra={"source": "task2_run_once_manual"},
|
||||
)
|
||||
return result
|
||||
except Exception as e:
|
||||
if started_sync_here and logger.get_active_sync_id():
|
||||
logger.end_sync_with_stats(
|
||||
stats={},
|
||||
success=False,
|
||||
error_message=str(e),
|
||||
extra={
|
||||
"source": "task2_run_once_manual",
|
||||
"exception_type": type(e).__name__,
|
||||
},
|
||||
)
|
||||
raise
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("=== 任务二同步服务测试 ===\n")
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user