move job scheduling to DB
This commit is contained in:
+1
-2
@@ -29,10 +29,9 @@ PORT=8080
|
|||||||
# Download settings
|
# Download settings
|
||||||
# DOWNLOAD_PARALLEL_LIMIT: Max concurrent downloads
|
# DOWNLOAD_PARALLEL_LIMIT: Max concurrent downloads
|
||||||
# DOWNLOAD_RATE_LIMIT: Seconds between requests (to avoid rate limiting)
|
# DOWNLOAD_RATE_LIMIT: Seconds between requests (to avoid rate limiting)
|
||||||
# DEFAULT_CHECK_INTERVAL: Seconds between automatic checks for new content
|
# Check interval is configured per-source in the web UI (Settings page)
|
||||||
DOWNLOAD_PARALLEL_LIMIT=3
|
DOWNLOAD_PARALLEL_LIMIT=3
|
||||||
DOWNLOAD_RATE_LIMIT=3.0
|
DOWNLOAD_RATE_LIMIT=3.0
|
||||||
DEFAULT_CHECK_INTERVAL=3600
|
|
||||||
|
|
||||||
# Logging level (DEBUG, INFO, WARNING, ERROR)
|
# Logging level (DEBUG, INFO, WARNING, ERROR)
|
||||||
LOG_LEVEL=INFO
|
LOG_LEVEL=INFO
|
||||||
|
|||||||
@@ -31,6 +31,29 @@ async def get_or_create_extension_api_key(session: AsyncSession) -> str:
|
|||||||
return new_key
|
return new_key
|
||||||
|
|
||||||
|
|
||||||
|
async def get_setting_value(session: AsyncSession, key: str, default=None):
|
||||||
|
"""Get a setting value from the database, falling back to defaults.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
session: Database session
|
||||||
|
key: Setting key (e.g., 'download.schedule_interval')
|
||||||
|
default: Fallback if not in database or DEFAULT_SETTINGS
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The setting value
|
||||||
|
"""
|
||||||
|
result = await session.execute(
|
||||||
|
select(Setting).where(Setting.key == key)
|
||||||
|
)
|
||||||
|
setting = result.scalar()
|
||||||
|
|
||||||
|
if setting:
|
||||||
|
return setting.value
|
||||||
|
|
||||||
|
# Fall back to DEFAULT_SETTINGS, then to provided default
|
||||||
|
return DEFAULT_SETTINGS.get(key, default)
|
||||||
|
|
||||||
|
|
||||||
@bp.route("", methods=["GET"])
|
@bp.route("", methods=["GET"])
|
||||||
async def get_all_settings():
|
async def get_all_settings():
|
||||||
"""Get all application settings."""
|
"""Get all application settings."""
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ from sqlalchemy.orm import selectinload
|
|||||||
from app.models.source import Source
|
from app.models.source import Source
|
||||||
from app.models.subscription import Subscription
|
from app.models.subscription import Subscription
|
||||||
from app.tasks.downloads import download_source
|
from app.tasks.downloads import download_source
|
||||||
|
from app.api.settings import get_setting_value
|
||||||
|
|
||||||
bp = Blueprint("sources", __name__)
|
bp = Blueprint("sources", __name__)
|
||||||
|
|
||||||
@@ -100,12 +101,17 @@ async def create_source():
|
|||||||
if existing.scalar():
|
if existing.scalar():
|
||||||
return jsonify({"error": "Source with this platform and URL already exists"}), 409
|
return jsonify({"error": "Source with this platform and URL already exists"}), 409
|
||||||
|
|
||||||
|
# Get default check interval from database settings
|
||||||
|
default_interval = await get_setting_value(
|
||||||
|
session, "download.schedule_interval", 3600
|
||||||
|
)
|
||||||
|
|
||||||
source = Source(
|
source = Source(
|
||||||
subscription_id=data["subscription_id"],
|
subscription_id=data["subscription_id"],
|
||||||
platform=data["platform"],
|
platform=data["platform"],
|
||||||
url=data["url"],
|
url=data["url"],
|
||||||
enabled=data.get("enabled", True),
|
enabled=data.get("enabled", True),
|
||||||
check_interval=data.get("check_interval", 3600),
|
check_interval=data.get("check_interval", default_interval),
|
||||||
metadata_=data.get("metadata", {}),
|
metadata_=data.get("metadata", {}),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ from sqlalchemy.orm import selectinload
|
|||||||
from app.models.subscription import Subscription
|
from app.models.subscription import Subscription
|
||||||
from app.models.source import Source
|
from app.models.source import Source
|
||||||
from app.tasks.downloads import download_source
|
from app.tasks.downloads import download_source
|
||||||
|
from app.api.settings import get_setting_value
|
||||||
|
|
||||||
bp = Blueprint("subscriptions", __name__)
|
bp = Blueprint("subscriptions", __name__)
|
||||||
|
|
||||||
@@ -85,6 +86,11 @@ async def create_subscription():
|
|||||||
metadata_=data.get("metadata", {}),
|
metadata_=data.get("metadata", {}),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Get default check interval from database settings
|
||||||
|
default_interval = await get_setting_value(
|
||||||
|
session, "download.schedule_interval", 3600
|
||||||
|
)
|
||||||
|
|
||||||
# Add sources if provided
|
# Add sources if provided
|
||||||
sources_data = data.get("sources", [])
|
sources_data = data.get("sources", [])
|
||||||
for source_data in sources_data:
|
for source_data in sources_data:
|
||||||
@@ -94,7 +100,7 @@ async def create_subscription():
|
|||||||
platform=source_data["platform"],
|
platform=source_data["platform"],
|
||||||
url=source_data["url"],
|
url=source_data["url"],
|
||||||
enabled=source_data.get("enabled", True),
|
enabled=source_data.get("enabled", True),
|
||||||
check_interval=source_data.get("check_interval", 3600),
|
check_interval=source_data.get("check_interval", default_interval),
|
||||||
metadata_=source_data.get("metadata", {}),
|
metadata_=source_data.get("metadata", {}),
|
||||||
)
|
)
|
||||||
subscription.sources.append(source)
|
subscription.sources.append(source)
|
||||||
@@ -254,12 +260,17 @@ async def add_source_to_subscription(subscription_id: int):
|
|||||||
# Store name before commit (attributes expire after commit)
|
# Store name before commit (attributes expire after commit)
|
||||||
subscription_name = subscription.name
|
subscription_name = subscription.name
|
||||||
|
|
||||||
|
# Get default check interval from database settings
|
||||||
|
default_interval = await get_setting_value(
|
||||||
|
session, "download.schedule_interval", 3600
|
||||||
|
)
|
||||||
|
|
||||||
source = Source(
|
source = Source(
|
||||||
subscription_id=subscription_id,
|
subscription_id=subscription_id,
|
||||||
platform=data["platform"],
|
platform=data["platform"],
|
||||||
url=data["url"],
|
url=data["url"],
|
||||||
enabled=data.get("enabled", True),
|
enabled=data.get("enabled", True),
|
||||||
check_interval=data.get("check_interval", 3600),
|
check_interval=data.get("check_interval", default_interval),
|
||||||
metadata_=data.get("metadata", {}),
|
metadata_=data.get("metadata", {}),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ class Settings(BaseSettings):
|
|||||||
# Download settings
|
# Download settings
|
||||||
download_parallel_limit: int = 3
|
download_parallel_limit: int = 3
|
||||||
download_rate_limit: float = 3.0
|
download_rate_limit: float = 3.0
|
||||||
default_check_interval: int = 3600 # seconds
|
# Note: check_interval is now per-source and stored in database
|
||||||
|
|
||||||
# Server
|
# Server
|
||||||
host: str = "0.0.0.0"
|
host: str = "0.0.0.0"
|
||||||
|
|||||||
@@ -28,10 +28,13 @@ celery_app.conf.update(
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Celery Beat schedule for periodic tasks
|
# Celery Beat schedule for periodic tasks
|
||||||
|
# Note: The scheduler runs frequently (every 60s) but only triggers downloads
|
||||||
|
# for sources whose individual check_interval has elapsed. Per-source intervals
|
||||||
|
# are stored in the database and can be configured via the UI.
|
||||||
celery_app.conf.beat_schedule = {
|
celery_app.conf.beat_schedule = {
|
||||||
"check-sources-hourly": {
|
"check-sources-scheduler": {
|
||||||
"task": "app.tasks.downloads.scheduled_check",
|
"task": "app.tasks.downloads.scheduled_check",
|
||||||
"schedule": settings.default_check_interval, # Default: every hour
|
"schedule": 60, # Run every 60 seconds to check for due sources
|
||||||
},
|
},
|
||||||
"cleanup-old-downloads-daily": {
|
"cleanup-old-downloads-daily": {
|
||||||
"task": "app.tasks.downloads.cleanup_old_downloads",
|
"task": "app.tasks.downloads.cleanup_old_downloads",
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ services:
|
|||||||
- SECRET_KEY=${SECRET_KEY:-dev-secret-key-not-for-production}
|
- SECRET_KEY=${SECRET_KEY:-dev-secret-key-not-for-production}
|
||||||
- DOWNLOAD_PARALLEL_LIMIT=${DOWNLOAD_PARALLEL_LIMIT:-3}
|
- DOWNLOAD_PARALLEL_LIMIT=${DOWNLOAD_PARALLEL_LIMIT:-3}
|
||||||
- DOWNLOAD_RATE_LIMIT=${DOWNLOAD_RATE_LIMIT:-3.0}
|
- DOWNLOAD_RATE_LIMIT=${DOWNLOAD_RATE_LIMIT:-3.0}
|
||||||
- DEFAULT_CHECK_INTERVAL=${DEFAULT_CHECK_INTERVAL:-3600}
|
|
||||||
- LOG_LEVEL=DEBUG
|
- LOG_LEVEL=DEBUG
|
||||||
- DEBUG=true
|
- DEBUG=true
|
||||||
volumes:
|
volumes:
|
||||||
@@ -47,7 +46,6 @@ services:
|
|||||||
- SECRET_KEY=${SECRET_KEY:-dev-secret-key-not-for-production}
|
- SECRET_KEY=${SECRET_KEY:-dev-secret-key-not-for-production}
|
||||||
- DOWNLOAD_PARALLEL_LIMIT=${DOWNLOAD_PARALLEL_LIMIT:-3}
|
- DOWNLOAD_PARALLEL_LIMIT=${DOWNLOAD_PARALLEL_LIMIT:-3}
|
||||||
- DOWNLOAD_RATE_LIMIT=${DOWNLOAD_RATE_LIMIT:-3.0}
|
- DOWNLOAD_RATE_LIMIT=${DOWNLOAD_RATE_LIMIT:-3.0}
|
||||||
- DEFAULT_CHECK_INTERVAL=${DEFAULT_CHECK_INTERVAL:-3600}
|
|
||||||
- LOG_LEVEL=DEBUG
|
- LOG_LEVEL=DEBUG
|
||||||
- DEBUG=true
|
- DEBUG=true
|
||||||
volumes:
|
volumes:
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ services:
|
|||||||
- SECRET_KEY=${SECRET_KEY}
|
- SECRET_KEY=${SECRET_KEY}
|
||||||
- DOWNLOAD_PARALLEL_LIMIT=${DOWNLOAD_PARALLEL_LIMIT:-3}
|
- DOWNLOAD_PARALLEL_LIMIT=${DOWNLOAD_PARALLEL_LIMIT:-3}
|
||||||
- DOWNLOAD_RATE_LIMIT=${DOWNLOAD_RATE_LIMIT:-3.0}
|
- DOWNLOAD_RATE_LIMIT=${DOWNLOAD_RATE_LIMIT:-3.0}
|
||||||
- DEFAULT_CHECK_INTERVAL=${DEFAULT_CHECK_INTERVAL:-3600}
|
|
||||||
- LOG_LEVEL=${LOG_LEVEL:-INFO}
|
- LOG_LEVEL=${LOG_LEVEL:-INFO}
|
||||||
volumes:
|
volumes:
|
||||||
- ${DATA_DOWNLOADS:-downloads}:/data/downloads
|
- ${DATA_DOWNLOADS:-downloads}:/data/downloads
|
||||||
@@ -43,7 +42,6 @@ services:
|
|||||||
- SECRET_KEY=${SECRET_KEY}
|
- SECRET_KEY=${SECRET_KEY}
|
||||||
- DOWNLOAD_PARALLEL_LIMIT=${DOWNLOAD_PARALLEL_LIMIT:-3}
|
- DOWNLOAD_PARALLEL_LIMIT=${DOWNLOAD_PARALLEL_LIMIT:-3}
|
||||||
- DOWNLOAD_RATE_LIMIT=${DOWNLOAD_RATE_LIMIT:-3.0}
|
- DOWNLOAD_RATE_LIMIT=${DOWNLOAD_RATE_LIMIT:-3.0}
|
||||||
- DEFAULT_CHECK_INTERVAL=${DEFAULT_CHECK_INTERVAL:-3600}
|
|
||||||
- LOG_LEVEL=${LOG_LEVEL:-INFO}
|
- LOG_LEVEL=${LOG_LEVEL:-INFO}
|
||||||
volumes:
|
volumes:
|
||||||
- ${DATA_DOWNLOADS:-downloads}:/data/downloads
|
- ${DATA_DOWNLOADS:-downloads}:/data/downloads
|
||||||
|
|||||||
Reference in New Issue
Block a user