Files

87 lines
4.3 KiB
Python

"""Background runtime startup; skipped for one-shot CLI invocations."""
import os
import sys
def start_runtime(app):
# Background daemons (metrics collector, queue consumers, analytics
# flush, the job system, the linked-panel client) only make sense in a
# long-running server process. When the app is loaded by a Flask CLI
# one-shot — crucially `flask db upgrade` during an update — they must
# NOT start: they query the database before migrations have run, and
# any failure there (a corrupt DB, or pre-migration schema the new code
# doesn't match yet) aborts the CLI command and sinks the whole update.
# SERVERKIT_SKIP_BACKGROUND=1 forces the same skip; the updater sets it
# as an explicit contract when running migrations.
_cli_one_shot = (
os.path.basename(sys.argv[0] or '').startswith('flask')
and (len(sys.argv) < 2 or sys.argv[1] != 'run')
)
from app.utils.env import env_bool
_skip_background = env_bool('SERVERKIT_SKIP_BACKGROUND') or _cli_one_shot
if not _skip_background:
# Before any consumer polls: release what the previous process
# left in flight, or it stays stranded forever.
if not app.config.get('TESTING'):
from app.jobs.service import JobService
try:
JobService.recover_interrupted()
except Exception:
import logging
logging.getLogger(__name__).exception('Interrupted-job recovery failed')
from app.bootstrap.agents import start_agent_runtime
start_agent_runtime(app)
# Start metrics history collection in background
from app.services.metrics_history_service import MetricsHistoryService
if not MetricsHistoryService.is_running():
MetricsHistoryService.start_collection(app)
# Start queue-bus webhook consumer
from app.queue_bus.consumers import start_webhook_consumer
start_webhook_consumer(app)
# Start queue-bus notification consumer (delivers in-app/email/chat)
from app.notifications.consumer import start_notification_consumer
start_notification_consumer(app)
# Start the API analytics flush thread (a 5s buffer flush — a real-time
# stream, deliberately NOT modeled as a job).
from app.middleware.api_analytics import start_analytics_flush_thread
start_analytics_flush_thread(app)
# Start the unified job system: ONE consumer runs every enqueued Job and
# ONE scheduler ticks all periodic work. This supersedes the former set
# of per-domain daemon scheduler threads (auto-sync, snapshot-retention,
# workflow, health-check, wp-update, api-background, pairing-prune,
# registrar-expiry) — they are now ScheduledJob rows backed by the
# built-in handlers in app/jobs/builtin_handlers.py.
from app.jobs import start_job_system
from app.bootstrap.jobs import register_job_handlers
seed_builtin_schedules = register_job_handlers(app)
start_job_system(app, seed=seed_builtin_schedules)
# Threshold alerting and the uptime sampler are switched on from
# the UI; without this they silently stop at the next restart
# while their status still reads "enabled".
# Best effort: a resume failure must never stop the panel booting.
if not app.config.get('TESTING'):
from app.services.monitoring_service import MonitoringService
from app.services.uptime_service import UptimeService
for resume in (lambda: MonitoringService.resume_if_enabled(app),
UptimeService.resume_if_enabled):
try:
resume()
except Exception: # noqa: BLE001
app.logger.exception('Could not resume a background monitor at boot')
# Resume the embedded agent when this panel is linked to a master
# ServerKit panel (ServerKit-to-ServerKit peering).
from app.services.linked_panel_service import LinkedPanelService
LinkedPanelService.start_client_if_linked(app)
# Hold the outbound ServerKit Cloud relay connection when this
# panel is paired.
from app.services import connect_client
connect_client.start_client_if_paired(app)