Files
ecm_sync_system/sync_state_machine/datasource/task_result.py
T
strepsiades 4a9c444b10 first commit
2026-03-09 16:31:42 +08:00

123 lines
4.0 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.
"""
TaskResult - Handler 执行结果
统一的任务执行结果,用于所有 DataSource 的 Handler。
"""
from enum import Enum
from typing import Dict, Any, Optional
class TaskStatus(Enum):
"""任务执行状态"""
SUCCESS = "success" # 同步完成,立即成功
FAILED = "failed" # 同步失败
IN_PROGRESS = "in_progress" # 异步任务进行中
SKIPPED = "skipped" # 跳过(无实际更新或不符合更新条件)
class TaskResult:
"""
Handler 执行结果
用于封装 create/update/delete 操作的返回值。
适用于所有 DataSourceAPI、JSONL 等)。
支持批量操作时通过 node_id 定位结果。
"""
def __init__(
self,
status: TaskStatus,
node_id: Optional[str] = None,
data_id: Optional[str] = None,
task_id: Optional[str] = None,
push_id: Optional[str] = None,
error: Optional[str] = None,
sync_log: Optional[str] = None,
metadata: Optional[Dict[str, Any]] = None
):
"""
Args:
status: 任务状态(SUCCESS/FAILED/IN_PROGRESS
node_id: 关联的节点 ID(批量操作时用于定位节点)
data_id: 成功时返回的业务 IDCREATE 操作必需)
task_id: 异步任务 IDstatus=IN_PROGRESS 时必需)
push_id: 推送请求 ID(用于统一 push/poll 跟踪)
error: 失败原因(status=FAILED 时必需)
sync_log: Debug/Info级别日志(SKIPPED时使用)
metadata: 其他元数据
"""
normalized_metadata = dict(metadata or {})
if push_id is None:
raw_push_id = normalized_metadata.get("push_id")
if isinstance(raw_push_id, str) and raw_push_id:
push_id = raw_push_id
elif push_id:
normalized_metadata.setdefault("push_id", push_id)
self.status = status
self.node_id = node_id
self.data_id = data_id
self.task_id = task_id
self.push_id = push_id
self.error = error
self.sync_log = sync_log
self.metadata = normalized_metadata
@classmethod
def success(
cls,
node_id: Optional[str] = None,
data_id: Optional[str] = None,
push_id: Optional[str] = None,
**metadata,
) -> "TaskResult":
"""创建成功结果"""
return cls(TaskStatus.SUCCESS, node_id=node_id, data_id=data_id, push_id=push_id, metadata=metadata)
@classmethod
def failed(
cls,
node_id: Optional[str] = None,
error: str = "",
push_id: Optional[str] = None,
**metadata,
) -> "TaskResult":
"""创建失败结果"""
return cls(TaskStatus.FAILED, node_id=node_id, error=error, push_id=push_id, metadata=metadata)
@classmethod
def skipped(
cls,
node_id: Optional[str] = None,
reason: str = "",
push_id: Optional[str] = None,
**metadata,
) -> "TaskResult":
"""创建跳过结果(无实际更新等)"""
return cls(TaskStatus.SKIPPED, node_id=node_id, sync_log=reason, push_id=push_id, metadata=metadata)
@classmethod
def in_progress(
cls,
node_id: Optional[str] = None,
task_id: str = "",
push_id: Optional[str] = None,
**metadata,
) -> "TaskResult":
"""创建进行中结果"""
return cls(TaskStatus.IN_PROGRESS, node_id=node_id, task_id=task_id, push_id=push_id, metadata=metadata)
def __repr__(self) -> str:
parts = [f"status={self.status.value}"]
if self.node_id:
parts.append(f"node_id={self.node_id}")
if self.data_id:
parts.append(f"data_id={self.data_id}")
if self.task_id:
parts.append(f"task_id={self.task_id}")
if self.push_id:
parts.append(f"push_id={self.push_id}")
if self.error:
parts.append(f"error={self.error!r}")
return f"TaskResult({', '.join(parts)})"