Initial commit: scheduler service extraction from portainer-core
Build and Push / build (release) Failing after 17s
Build and Push / build (release) Failing after 17s
Extracted standalone scheduler service with: - FastAPI REST API for task management - APScheduler-based task execution - PostgreSQL persistence - Docker container support - Gitea Actions CI/CD workflow 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
+210
@@ -0,0 +1,210 @@
|
||||
"""
|
||||
Pydantic models for The Scheduler API.
|
||||
"""
|
||||
from pydantic import BaseModel, Field
|
||||
from typing import Optional, Dict, Any
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class SchedulePattern(str, Enum):
|
||||
"""Common schedule patterns."""
|
||||
EVERY_MINUTE = "every_minute"
|
||||
HOURLY = "hourly"
|
||||
DAILY = "daily"
|
||||
WEEKLY = "weekly"
|
||||
MONTHLY = "monthly"
|
||||
|
||||
|
||||
class TaskExecutor(str, Enum):
|
||||
"""Available task executors."""
|
||||
REST_API = "rest_api"
|
||||
SHELL = "shell"
|
||||
PYTHON = "python"
|
||||
|
||||
|
||||
class TaskPriorityLevel(str, Enum):
|
||||
"""Task priority levels."""
|
||||
EMERGENCY = "emergency" # 1-5: Critical system tasks
|
||||
SYSTEM = "system" # 5-10: System maintenance
|
||||
USER = "user" # 10-30: User-initiated tasks
|
||||
MAINTENANCE = "maintenance" # 40-70: Background maintenance
|
||||
LOW = "low" # 70+: Low priority cleanup
|
||||
|
||||
|
||||
class TaskBase(BaseModel):
|
||||
"""Base task fields."""
|
||||
task_name: str = Field(
|
||||
...,
|
||||
description="Unique task identifier (e.g., 'librarian_consolidation')",
|
||||
example="librarian_consolidation"
|
||||
)
|
||||
service: str = Field(
|
||||
...,
|
||||
description="Service that owns this task (e.g., 'library-desk', 'core-api')",
|
||||
example="library-desk"
|
||||
)
|
||||
executor: str = Field(
|
||||
...,
|
||||
description="Executor type: 'rest_api', 'shell', or 'python'",
|
||||
example="rest_api"
|
||||
)
|
||||
priority: int = Field(
|
||||
...,
|
||||
ge=1,
|
||||
le=100,
|
||||
description="Priority level (1-5: emergency, 10-30: user, 40-70: maintenance, 70+: low)",
|
||||
example=25
|
||||
)
|
||||
description: Optional[str] = Field(
|
||||
None,
|
||||
description="Human-readable task description",
|
||||
example="Processes unprocessed search queries and consolidates knowledge into wiki pages"
|
||||
)
|
||||
|
||||
|
||||
class TaskSchedule(BaseModel):
|
||||
"""Cron-style schedule fields."""
|
||||
minute: int = Field(
|
||||
-1,
|
||||
ge=-1,
|
||||
le=59,
|
||||
description="Minute to run (-1 = every minute, 0-59 = specific minute)",
|
||||
example=-1
|
||||
)
|
||||
hour: int = Field(
|
||||
-1,
|
||||
ge=-1,
|
||||
le=23,
|
||||
description="Hour to run (-1 = every hour, 0-23 = specific hour)",
|
||||
example=-1
|
||||
)
|
||||
day_of_month: int = Field(
|
||||
-1,
|
||||
ge=-1,
|
||||
le=31,
|
||||
description="Day of month to run (-1 = every day, 1-31 = specific day)",
|
||||
example=-1
|
||||
)
|
||||
month: int = Field(
|
||||
-1,
|
||||
ge=-1,
|
||||
le=12,
|
||||
description="Month to run (-1 = every month, 1-12 = specific month)",
|
||||
example=-1
|
||||
)
|
||||
day_of_week: int = Field(
|
||||
-1,
|
||||
ge=-1,
|
||||
le=6,
|
||||
description="Day of week to run (-1 = every day, 0-6 = Monday-Sunday)",
|
||||
example=-1
|
||||
)
|
||||
|
||||
|
||||
class TaskConfig(BaseModel):
|
||||
"""Task execution configuration."""
|
||||
enabled: bool = Field(
|
||||
True,
|
||||
description="Whether task is enabled",
|
||||
example=True
|
||||
)
|
||||
max_retries: int = Field(
|
||||
3,
|
||||
ge=0,
|
||||
le=10,
|
||||
description="Maximum retry attempts on failure",
|
||||
example=3
|
||||
)
|
||||
timeout_seconds: int = Field(
|
||||
3600,
|
||||
ge=1,
|
||||
description="Execution timeout in seconds",
|
||||
example=3600
|
||||
)
|
||||
config: Optional[Dict[str, Any]] = Field(
|
||||
None,
|
||||
description="Executor-specific configuration (varies by executor type)",
|
||||
example={
|
||||
"method": "POST",
|
||||
"url": "http://library-desk:8089/consolidation/run",
|
||||
"headers": {
|
||||
"Authorization": "Bearer ${LIBRARY_DESK_API_KEY}",
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
"body": {
|
||||
"dry_run": False,
|
||||
"process_limit": 10,
|
||||
"lookback_days": 7,
|
||||
"min_web_results": 2
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
class TaskCreate(TaskBase, TaskSchedule, TaskConfig):
|
||||
"""Request model for creating a new scheduled task."""
|
||||
created_by: Optional[str] = Field(
|
||||
"api",
|
||||
description="User or system that created this task",
|
||||
example="api"
|
||||
)
|
||||
|
||||
class Config:
|
||||
json_schema_extra = {
|
||||
"example": {
|
||||
"task_name": "librarian_consolidation",
|
||||
"service": "library-desk",
|
||||
"executor": "rest_api",
|
||||
"priority": 25,
|
||||
"description": "Processes unprocessed search queries and consolidates knowledge",
|
||||
"minute": 0,
|
||||
"hour": -1,
|
||||
"day_of_month": -1,
|
||||
"month": -1,
|
||||
"day_of_week": -1,
|
||||
"enabled": True,
|
||||
"max_retries": 3,
|
||||
"timeout_seconds": 3600,
|
||||
"config": {
|
||||
"method": "POST",
|
||||
"url": "http://library-desk:8089/consolidation/run",
|
||||
"headers": {
|
||||
"Authorization": "Bearer ${LIBRARY_DESK_API_KEY}",
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
"body": {
|
||||
"dry_run": False,
|
||||
"process_limit": 10,
|
||||
"lookback_days": 7,
|
||||
"min_web_results": 2
|
||||
}
|
||||
},
|
||||
"created_by": "api"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class TaskUpdate(BaseModel):
|
||||
"""Request model for updating a scheduled task."""
|
||||
service: Optional[str] = None
|
||||
executor: Optional[str] = None
|
||||
priority: Optional[int] = Field(None, ge=1, le=100)
|
||||
minute: Optional[int] = Field(None, ge=-1, le=59)
|
||||
hour: Optional[int] = Field(None, ge=-1, le=23)
|
||||
day_of_month: Optional[int] = Field(None, ge=-1, le=31)
|
||||
month: Optional[int] = Field(None, ge=-1, le=12)
|
||||
day_of_week: Optional[int] = Field(None, ge=-1, le=6)
|
||||
enabled: Optional[bool] = None
|
||||
description: Optional[str] = None
|
||||
config: Optional[Dict[str, Any]] = None
|
||||
max_retries: Optional[int] = Field(None, ge=0, le=10)
|
||||
timeout_seconds: Optional[int] = Field(None, ge=1)
|
||||
|
||||
|
||||
class TaskResponse(TaskCreate):
|
||||
"""Response model for task operations."""
|
||||
created_at: str
|
||||
updated_at: Optional[str] = None
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
Reference in New Issue
Block a user