From 5dddd8224093dc0c41ba7dd876221e99425363d8 Mon Sep 17 00:00:00 2001 From: tecnotel Date: Mon, 4 May 2026 21:03:48 +0200 Subject: [PATCH] Update setup_server.py --- setup_server.py | 54 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 43 insertions(+), 11 deletions(-) diff --git a/setup_server.py b/setup_server.py index 18c9347..e1be876 100644 --- a/setup_server.py +++ b/setup_server.py @@ -559,32 +559,64 @@ def _write_nginx_conf(conf): def _write_services(): - venv_py = str(APP_DIR / "backend/venv/bin/python3") - backend_dir = str(APP_DIR / "backend") + """Genera le 4 unit systemd ARGOS in versione Gunicorn. + + Mappatura service → wsgi target: + - argos-backend : argos_backend:app (no wrapper, app a top-level) + - argos-sync : argos_sync_wsgi:app (wrapper avvia main_loop) + - argos-ops : argos_ops_wsgi:app (wrapper avvia main_loop) + - argos-analytics : argos_analytics_wsgi:app (wrapper avvia _scheduler_loop) + + Vincolo critico: workers=1 obbligatorio per sync/ops/analytics. + Hanno scheduler in-memory + thread daemon che, con N worker, sarebbero + duplicati N volte (job doppi, file lock contention, race su SQLite). + + Backend e' API stateless: 2 worker sync per migliorare throughput. + Gli altri usano gthread (threads=4) per servire API mentre lo scheduler + interno gira nel thread daemon. + + Aggiornato 04/05/2026: migrazione da Flask dev server a Gunicorn 25.3+. + """ + venv_bin = str(APP_DIR / "backend/venv/bin") + backend_dir = str(APP_DIR / "backend") + services_dir = str(APP_DIR / "backend/services") + + # (wsgi_target, workers, threads, timeout_sec, port, description) services = { - "backend": ("services/argos_backend.py", "Backend API"), - "sync": ("services/argos_sync.py", "Sync Daemon"), - "ops": ("services/argos_ops.py", "Ops Daemon"), - "analytics": ("services/argos_analytics.py", "Analytics Daemon"), + "backend": ("argos_backend:app", 2, 1, 120, 8080, "Backend API"), + "sync": ("argos_sync_wsgi:app", 1, 4, 600, 8081, "Sync Daemon"), + "ops": ("argos_ops_wsgi:app", 1, 4, 600, 8082, "Ops Daemon"), + "analytics": ("argos_analytics_wsgi:app", 1, 4, 300, 8083, "Analytics Daemon"), } - for svc, (script, desc) in services.items(): + for svc, (wsgi, workers, threads, timeout, port, desc) in services.items(): + # Solo i servizi con threads>1 usano gthread; backend e' sync con 2 worker. + threads_line = f" --threads {threads} \\\n" if threads > 1 else "" unit = f"""[Unit] -Description=ARGOS {desc} +Description=ARGOS {desc} (Gunicorn) After=network.target [Service] Type=simple User={APP_USER} Group={APP_USER} -WorkingDirectory={backend_dir} -Environment=PYTHONPATH={backend_dir} +WorkingDirectory={services_dir} +Environment=PYTHONPATH={backend_dir}:{services_dir} Environment=CONFIG_FILE={CONFIG_DIR}/argos.json Environment=INTEGRATIONS_FILE={CONFIG_DIR}/integrations.json Environment=DATA_DIR={DATA_DIR} Environment=FEEDS_DIR={FEEDS_DIR} Environment=LOGS_DIR={LOGS_DIR} -ExecStart={venv_py} {backend_dir}/{script} +ExecStart={venv_bin}/gunicorn {wsgi} \\ + --workers {workers} \\ +{threads_line} --bind 127.0.0.1:{port} \\ + --timeout {timeout} \\ + --graceful-timeout 30 \\ + --keep-alive 5 \\ + --access-logfile - \\ + --error-logfile - \\ + --log-level info \\ + --capture-output Restart=always RestartSec=5 StandardOutput=journal