base.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. """Task 领域 —— 任务抽象、处理器基类、注册表
  2. 所有任务概念集中于此,替代旧的分散在 jobs/task_*.py 的全局注册表模式。
  3. """
  4. from __future__ import annotations
  5. from abc import ABC, abstractmethod
  6. from dataclasses import dataclass, field
  7. from typing import Any, Callable, Dict, List, Optional
  8. from supply.domain.task.config import TaskConfig, TaskStatus, get_default_task_config
  9. from supply.domain.task.exceptions import (
  10. TaskError,
  11. TaskValidationError,
  12. TaskTimeoutError,
  13. TaskConcurrencyError,
  14. TaskLockError,
  15. )
  16. # ==================== Task / TaskResult ====================
  17. @dataclass
  18. class Task:
  19. """任务数据模型"""
  20. task_name: str
  21. params: Dict[str, Any] = field(default_factory=dict)
  22. trace_id: str = ""
  23. config: Optional[TaskConfig] = None
  24. @dataclass
  25. class TaskResult:
  26. """任务执行结果"""
  27. success: bool
  28. data: Any = None
  29. error: Optional[str] = None
  30. trace_id: str = ""
  31. @classmethod
  32. def ok(cls, data: Any = None, trace_id: str = "") -> "TaskResult":
  33. return cls(success=True, data=data, trace_id=trace_id)
  34. @classmethod
  35. def fail(cls, error: str, trace_id: str = "") -> "TaskResult":
  36. return cls(success=False, error=error, trace_id=trace_id)
  37. # ==================== TaskRegistry(实例级) ====================
  38. class TaskRegistry:
  39. """任务注册表 —— 实例级,替代全局 _TASK_HANDLER_REGISTRY
  40. 使用方式:
  41. registry = TaskRegistry()
  42. @registry.register("content_generation")
  43. class ContentGenHandler(TaskHandler):
  44. ...
  45. handler = registry.get("content_generation")
  46. result = await handler.execute(task)
  47. """
  48. def __init__(self):
  49. self._handlers: Dict[str, type] = {}
  50. def register(self, task_name: str) -> Callable:
  51. """装饰器:将 TaskHandler 子类注册到注册表
  52. 使用方式:
  53. @registry.register("my_task")
  54. class MyHandler(TaskHandler):
  55. ...
  56. """
  57. def decorator(handler_cls: type) -> type:
  58. if not issubclass(handler_cls, TaskHandler):
  59. raise TypeError(
  60. f"@register 只能用于 TaskHandler 子类,收到 {handler_cls}"
  61. )
  62. if task_name in self._handlers:
  63. raise ValueError(f"任务 '{task_name}' 已注册")
  64. self._handlers[task_name] = handler_cls
  65. handler_cls.task_name = task_name
  66. return handler_cls
  67. return decorator
  68. def get(self, task_name: str) -> Optional[type]:
  69. return self._handlers.get(task_name)
  70. def list_names(self) -> List[str]:
  71. return list(self._handlers.keys())
  72. def __len__(self) -> int:
  73. return len(self._handlers)
  74. def __contains__(self, task_name: str) -> bool:
  75. return task_name in self._handlers
  76. # ==================== TaskHandler 抽象基类 ====================
  77. class TaskHandler(ABC):
  78. """任务处理器抽象基类
  79. 业务方继承此类实现具体任务逻辑:
  80. class ContentGenHandler(TaskHandler):
  81. task_name = "content_generation"
  82. async def validate(self, task: Task) -> bool:
  83. return "topic" in task.params
  84. async def execute(self, task: Task) -> TaskResult:
  85. ...
  86. task_name 类属性由 @TaskRegistry.register 装饰器自动设置。
  87. """
  88. task_name: str = ""
  89. def __init__(
  90. self,
  91. log_service: Any = None,
  92. db_client: Any = None,
  93. ):
  94. self.log_service = log_service
  95. self.db_client = db_client
  96. @abstractmethod
  97. async def execute(self, task: Task) -> TaskResult:
  98. """执行任务主逻辑"""
  99. ...
  100. async def validate(self, task: Task) -> bool:
  101. """校验任务参数,默认通过。子类可按需覆写"""
  102. return True
  103. async def on_success(self, task: Task) -> None:
  104. """任务成功回调(可选覆写)"""
  105. pass
  106. async def on_failure(self, task: Task, error: Exception) -> None:
  107. """任务失败回调(可选覆写)"""
  108. pass
  109. def __repr__(self) -> str:
  110. return f"<TaskHandler name={self.task_name}>"