128 lines
4.5 KiB
Python
128 lines
4.5 KiB
Python
# [DEF:TaskManagerModels:Module]
|
|
# @TIER: STANDARD
|
|
# @SEMANTICS: task, models, pydantic, enum, state
|
|
# @PURPOSE: Defines the data models and enumerations used by the Task Manager.
|
|
# @LAYER: Core
|
|
# @RELATION: Used by TaskManager and API routes.
|
|
# @INVARIANT: Task IDs are immutable once created.
|
|
# @CONSTRAINT: Must use Pydantic for data validation.
|
|
|
|
# [SECTION: IMPORTS]
|
|
import uuid
|
|
from datetime import datetime
|
|
from enum import Enum
|
|
from typing import Dict, Any, List, Optional
|
|
|
|
from pydantic import BaseModel, Field
|
|
# [/SECTION]
|
|
|
|
# [DEF:TaskStatus:Enum]
|
|
# @TIER: TRIVIAL
|
|
# @SEMANTICS: task, status, state, enum
|
|
# @PURPOSE: Defines the possible states a task can be in during its lifecycle.
|
|
class TaskStatus(str, Enum):
|
|
PENDING = "PENDING"
|
|
RUNNING = "RUNNING"
|
|
SUCCESS = "SUCCESS"
|
|
FAILED = "FAILED"
|
|
AWAITING_MAPPING = "AWAITING_MAPPING"
|
|
AWAITING_INPUT = "AWAITING_INPUT"
|
|
# [/DEF:TaskStatus:Enum]
|
|
|
|
# [DEF:LogLevel:Enum]
|
|
# @SEMANTICS: log, level, severity, enum
|
|
# @PURPOSE: Defines the possible log levels for task logging.
|
|
# @TIER: STANDARD
|
|
class LogLevel(str, Enum):
|
|
DEBUG = "DEBUG"
|
|
INFO = "INFO"
|
|
WARNING = "WARNING"
|
|
ERROR = "ERROR"
|
|
# [/DEF:LogLevel:Enum]
|
|
|
|
# [DEF:LogEntry:Class]
|
|
# @SEMANTICS: log, entry, record, pydantic
|
|
# @PURPOSE: A Pydantic model representing a single, structured log entry associated with a task.
|
|
# @TIER: CRITICAL
|
|
# @INVARIANT: Each log entry has a unique timestamp and source.
|
|
class LogEntry(BaseModel):
|
|
timestamp: datetime = Field(default_factory=datetime.utcnow)
|
|
level: str = Field(default="INFO")
|
|
message: str
|
|
source: str = Field(default="system") # Component attribution: plugin, superset_api, git, etc.
|
|
context: Optional[Dict[str, Any]] = None # Legacy field, kept for backward compatibility
|
|
metadata: Optional[Dict[str, Any]] = None # Structured metadata (e.g., dashboard_id, progress)
|
|
# [/DEF:LogEntry:Class]
|
|
|
|
# [DEF:TaskLog:Class]
|
|
# @SEMANTICS: task, log, persistent, pydantic
|
|
# @PURPOSE: A Pydantic model representing a persisted log entry from the database.
|
|
# @TIER: STANDARD
|
|
# @RELATION: MAPS_TO -> TaskLogRecord
|
|
class TaskLog(BaseModel):
|
|
id: int
|
|
task_id: str
|
|
timestamp: datetime
|
|
level: str
|
|
source: str
|
|
message: str
|
|
metadata: Optional[Dict[str, Any]] = None
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
# [/DEF:TaskLog:Class]
|
|
|
|
# [DEF:LogFilter:Class]
|
|
# @SEMANTICS: log, filter, query, pydantic
|
|
# @PURPOSE: Filter parameters for querying task logs.
|
|
# @TIER: STANDARD
|
|
class LogFilter(BaseModel):
|
|
level: Optional[str] = None # Filter by log level
|
|
source: Optional[str] = None # Filter by source component
|
|
search: Optional[str] = None # Text search in message
|
|
offset: int = Field(default=0, ge=0)
|
|
limit: int = Field(default=100, ge=1, le=1000)
|
|
# [/DEF:LogFilter:Class]
|
|
|
|
# [DEF:LogStats:Class]
|
|
# @SEMANTICS: log, stats, aggregation, pydantic
|
|
# @PURPOSE: Statistics about log entries for a task.
|
|
# @TIER: STANDARD
|
|
class LogStats(BaseModel):
|
|
total_count: int
|
|
by_level: Dict[str, int] # {"INFO": 10, "ERROR": 2}
|
|
by_source: Dict[str, int] # {"plugin": 5, "superset_api": 7}
|
|
# [/DEF:LogStats:Class]
|
|
|
|
# [DEF:Task:Class]
|
|
# @TIER: STANDARD
|
|
# @SEMANTICS: task, job, execution, state, pydantic
|
|
# @PURPOSE: A Pydantic model representing a single execution instance of a plugin, including its status, parameters, and logs.
|
|
class Task(BaseModel):
|
|
id: str = Field(default_factory=lambda: str(uuid.uuid4()))
|
|
plugin_id: str
|
|
status: TaskStatus = TaskStatus.PENDING
|
|
started_at: Optional[datetime] = None
|
|
finished_at: Optional[datetime] = None
|
|
user_id: Optional[str] = None
|
|
logs: List[LogEntry] = Field(default_factory=list)
|
|
params: Dict[str, Any] = Field(default_factory=dict)
|
|
input_required: bool = False
|
|
input_request: Optional[Dict[str, Any]] = None
|
|
# Result payload can be dict/list/scalar depending on plugin and legacy records.
|
|
result: Optional[Any] = None
|
|
|
|
# [DEF:__init__:Function]
|
|
# @PURPOSE: Initializes the Task model and validates input_request for AWAITING_INPUT status.
|
|
# @PRE: If status is AWAITING_INPUT, input_request must be provided.
|
|
# @POST: Task instance is created or ValueError is raised.
|
|
# @PARAM: **data - Keyword arguments for model initialization.
|
|
def __init__(self, **data):
|
|
super().__init__(**data)
|
|
if self.status == TaskStatus.AWAITING_INPUT and not self.input_request:
|
|
raise ValueError("input_request is required when status is AWAITING_INPUT")
|
|
# [/DEF:__init__:Function]
|
|
# [/DEF:Task:Class]
|
|
|
|
# [/DEF:TaskManagerModels:Module]
|