""" Task Registry System for Scheduled Jobs This module provides a decorator-based registration system for predefined tasks. Tasks are registered with their metadata, parameters schema, and execution function. """ import logging from typing import Dict, Callable, Any, List, Optional from dataclasses import dataclass, field from pydantic import BaseModel, Field logger = logging.getLogger(__name__) class TaskParameter(BaseModel): """Task parameter definition""" name: str = Field(..., description="Parameter name") type: str = Field(..., description="Parameter type (string, integer, array, boolean)") description: str = Field(..., description="Parameter description") required: bool = Field(default=False, description="Whether parameter is required") default: Any = Field(default=None, description="Default value") @dataclass class TaskDefinition: """Registered task definition""" name: str function: Callable description: str parameters: List[TaskParameter] = field(default_factory=list) category: str = "general" class TaskRegistry: """Registry for predefined scheduled tasks""" def __init__(self): self._tasks: Dict[str, TaskDefinition] = {} def register( self, name: str, description: str, parameters: Optional[List[Dict[str, Any]]] = None, category: str = "general" ): """ Decorator to register a task function Usage: @task_registry.register( name="sync_positions", description="Sync celestial body positions", parameters=[ {"name": "days", "type": "integer", "description": "Days to sync", "default": 7} ] ) async def sync_positions_task(db, logger, params): # Task implementation pass """ def decorator(func: Callable): # Parse parameters param_list = [] if parameters: for p in parameters: param_list.append(TaskParameter(**p)) # Register the task task_def = TaskDefinition( name=name, function=func, description=description, parameters=param_list, category=category ) self._tasks[name] = task_def logger.debug(f"Registered task: {name}") return func return decorator def get_task(self, name: str) -> Optional[TaskDefinition]: """Get a task definition by name""" return self._tasks.get(name) def list_tasks(self) -> List[Dict[str, Any]]: """List all registered tasks with their metadata""" return [ { "name": task.name, "description": task.description, "category": task.category, "parameters": [ { "name": p.name, "type": p.type, "description": p.description, "required": p.required, "default": p.default } for p in task.parameters ] } for task in self._tasks.values() ] async def execute_task( self, name: str, db: Any, logger: logging.Logger, params: Dict[str, Any] ) -> Any: """ Execute a registered task Args: name: Task function name db: Database session logger: Logger instance params: Task parameters from function_params JSONB field Returns: Task execution result Raises: ValueError: If task not found """ task_def = self.get_task(name) if not task_def: raise ValueError(f"Task '{name}' not found in registry") # Merge default parameters merged_params = {} for param in task_def.parameters: if param.name in params: merged_params[param.name] = params[param.name] elif param.default is not None: merged_params[param.name] = param.default elif param.required: raise ValueError(f"Required parameter '{param.name}' not provided") # Execute the task function logger.debug(f"Executing task '{name}' with params: {merged_params}") result = await task_def.function(db=db, logger=logger, params=merged_params) logger.debug(f"Task '{name}' completed successfully") return result # Global task registry instance task_registry = TaskRegistry()