mirror of
https://github.com/jhd3197/ServerKit.git
synced 2026-10-28 23:57:58 +09:00
87 lines
4.3 KiB
Python
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)
|