- T55: Setup APScheduler with AsyncIOScheduler and @scheduled_job decorator - T56: Implement hourly usage stats sync from OpenRouter API - T57: Implement daily API key validation job - T58: Implement weekly cleanup job for old usage stats - Add usage_stats_retention_days config option - Integrate scheduler with FastAPI lifespan events - Add 26 unit tests for scheduler, sync, and cleanup tasks - Add apscheduler to requirements.txt The background tasks now automatically: - Sync usage stats every hour from OpenRouter - Validate API keys daily at 2 AM UTC - Clean up old data weekly on Sunday at 3 AM UTC
112 lines
3.1 KiB
Python
112 lines
3.1 KiB
Python
"""Configuration management using Pydantic Settings.
|
|
|
|
This module provides centralized configuration management for the
|
|
OpenRouter API Key Monitor application.
|
|
"""
|
|
from functools import lru_cache
|
|
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
from pydantic import Field
|
|
|
|
|
|
class Settings(BaseSettings):
|
|
"""Application settings loaded from environment variables.
|
|
|
|
Required environment variables:
|
|
- SECRET_KEY: JWT signing key (min 32 chars)
|
|
- ENCRYPTION_KEY: AES-256 encryption key (32 bytes)
|
|
|
|
Optional environment variables with defaults:
|
|
- DATABASE_URL: SQLite database path
|
|
- OPENROUTER_API_URL: OpenRouter API base URL
|
|
- SYNC_INTERVAL_MINUTES: Background sync interval
|
|
- MAX_API_KEYS_PER_USER: API key limit per user
|
|
- RATE_LIMIT_REQUESTS: API rate limit
|
|
- RATE_LIMIT_WINDOW: Rate limit window (seconds)
|
|
- JWT_EXPIRATION_HOURS: JWT token lifetime
|
|
- DEBUG: Debug mode flag
|
|
- LOG_LEVEL: Logging level
|
|
"""
|
|
|
|
# Database
|
|
database_url: str = Field(
|
|
default="sqlite:///./data/app.db",
|
|
description="SQLite database URL"
|
|
)
|
|
|
|
# Security - REQUIRED
|
|
secret_key: str = Field(
|
|
description="JWT signing key (min 32 characters)"
|
|
)
|
|
encryption_key: str = Field(
|
|
description="AES-256 encryption key (32 bytes)"
|
|
)
|
|
jwt_expiration_hours: int = Field(
|
|
default=24,
|
|
description="JWT token expiration in hours"
|
|
)
|
|
|
|
# OpenRouter Integration
|
|
openrouter_api_url: str = Field(
|
|
default="https://openrouter.ai/api/v1",
|
|
description="OpenRouter API base URL"
|
|
)
|
|
|
|
# Task scheduling
|
|
sync_interval_minutes: int = Field(
|
|
default=60,
|
|
description="Background sync interval in minutes"
|
|
)
|
|
usage_stats_retention_days: int = Field(
|
|
default=365,
|
|
description="Retention period for usage stats in days"
|
|
)
|
|
|
|
# Limits
|
|
max_api_keys_per_user: int = Field(
|
|
default=10,
|
|
description="Maximum API keys per user"
|
|
)
|
|
max_api_tokens_per_user: int = Field(
|
|
default=5,
|
|
description="Maximum API tokens per user"
|
|
)
|
|
rate_limit_requests: int = Field(
|
|
default=100,
|
|
description="API rate limit requests"
|
|
)
|
|
rate_limit_window: int = Field(
|
|
default=3600,
|
|
description="Rate limit window in seconds"
|
|
)
|
|
|
|
# App settings
|
|
debug: bool = Field(
|
|
default=False,
|
|
description="Debug mode"
|
|
)
|
|
log_level: str = Field(
|
|
default="INFO",
|
|
description="Logging level"
|
|
)
|
|
|
|
model_config = SettingsConfigDict(
|
|
env_file=".env",
|
|
env_file_encoding="utf-8",
|
|
case_sensitive=False
|
|
)
|
|
|
|
|
|
@lru_cache()
|
|
def get_settings() -> Settings:
|
|
"""Get cached settings instance.
|
|
|
|
Returns:
|
|
Settings: Application settings instance
|
|
|
|
Example:
|
|
>>> from openrouter_monitor.config import get_settings
|
|
>>> settings = get_settings()
|
|
>>> print(settings.database_url)
|
|
"""
|
|
return Settings()
|