"""Scheduled task model for flexible task scheduling with timezone support.""" import uuid from datetime import datetime from enum import Enum from typing import Any, Optional from sqlmodel import JSON, Column, Field, SQLModel from app.models.base import BaseModel class TaskType(str, Enum): """Available task types.""" CREDIT_RECHARGE = "credit_recharge" PLAY_SOUND = "play_sound" PLAY_PLAYLIST = "play_playlist" class TaskStatus(str, Enum): """Task execution status.""" PENDING = "pending" RUNNING = "running" COMPLETED = "completed" FAILED = "failed" CANCELLED = "cancelled" class RecurrenceType(str, Enum): """Recurrence patterns.""" NONE = "none" # One-shot task HOURLY = "hourly" DAILY = "daily" WEEKLY = "weekly" MONTHLY = "monthly" YEARLY = "yearly" CRON = "cron" # Custom cron expression class ScheduledTask(BaseModel, table=True): """Model for scheduled tasks with timezone support.""" __tablename__ = "scheduled_tasks" id: int | None = Field(primary_key=True, default=None) name: str = Field(max_length=255, description="Human-readable task name") task_type: TaskType = Field(description="Type of task to execute") status: TaskStatus = Field(default=TaskStatus.PENDING) # Scheduling fields with timezone support scheduled_at: datetime = Field(description="When the task should be executed (UTC)") timezone: str = Field( default="UTC", description="Timezone for scheduling (e.g., 'America/New_York', 'Europe/Paris')", ) recurrence_type: RecurrenceType = Field(default=RecurrenceType.NONE) cron_expression: Optional[str] = Field( default=None, description="Cron expression for custom recurrence (when recurrence_type is CRON)", ) recurrence_count: Optional[int] = Field( default=None, description="Number of times to repeat (None for infinite)", ) executions_count: int = Field(default=0, description="Number of times executed") # Task parameters parameters: dict[str, Any] = Field( default_factory=dict, sa_column=Column(JSON), description="Task-specific parameters", ) # User association (None for system tasks) user_id: Optional[int] = Field( default=None, foreign_key="user.id", description="User who created the task (None for system tasks)", ) # Execution tracking last_executed_at: Optional[datetime] = Field( default=None, description="When the task was last executed (UTC)", ) next_execution_at: Optional[datetime] = Field( default=None, description="When the task should be executed next (UTC, for recurring tasks)", ) error_message: Optional[str] = Field( default=None, description="Error message if execution failed", ) # Task lifecycle is_active: bool = Field(default=True, description="Whether the task is active") expires_at: Optional[datetime] = Field( default=None, description="When the task expires (UTC, optional)", ) def is_expired(self) -> bool: """Check if the task has expired.""" if self.expires_at is None: return False return datetime.utcnow() > self.expires_at def is_recurring(self) -> bool: """Check if the task is recurring.""" return self.recurrence_type != RecurrenceType.NONE def should_repeat(self) -> bool: """Check if the task should be repeated.""" if not self.is_recurring(): return False if self.recurrence_count is None: return True return self.executions_count < self.recurrence_count def is_system_task(self) -> bool: """Check if this is a system task (no user association).""" return self.user_id is None