import os import socket from celery import Celery from celery.signals import worker_ready REDIS_URL = os.getenv("REDIS_URL", "redis://localhost:6379/0") celery_app = Celery( "rippy_worker", broker=REDIS_URL, backend=REDIS_URL, include=["tasks"] ) celery_app.conf.update( task_serializer="json", accept_content=["json"], result_serializer="json", timezone="UTC", enable_utc=True, broker_connection_retry_on_startup=True, # worker_direct: jeder Worker konsumiert zusätzlich eine eigene # Direkt-Queue (.dq). Damit kann die API die Kompression # gezielt an EINEN gewählten Worker schicken (Encoder-Auswahl im # Rip-Dialog) — ohne Wahl läuft sie weiter über die geteilte # transcode-Queue (irgendein freier Worker). worker_direct=True, ) # Import auf Modulebene: im worker_ready-Signal ist /app nicht mehr # zuverlässig im sys.path (ModuleNotFoundError 'caps', Deploy 23.07.). import caps # noqa: E402 import db # noqa: E402 @worker_ready.connect def melde_faehigkeiten(**kwargs): """Beim Start + minütlich: Encoder-Fähigkeiten und Lebenszeichen melden. last_seen ist die Basis der Erreichbarkeits-Anzeige im UI — ein Worker, der sich 2 Minuten nicht meldet, gilt als offline. """ import threading import time # Anzeigename: WORKER_NAME (compose/.env) macht die Maschine im UI # zuordenbar UND stabil — der Container-Hostname wechselt bei jedem # Rebuild und hinterließ Offline-Leichen in der Worker-Liste. anzeigename = os.getenv("WORKER_NAME") or socket.gethostname() def herzschlag(): while True: try: db.init_db() db.save_worker( anzeigename, caps.erkenne_encoder(), caps.werkzeug_versionen(), ) except Exception as e: # DB weg → weiterversuchen, nicht sterben print(f"Fähigkeiten-Meldung fehlgeschlagen: {e}") time.sleep(60) threading.Thread(target=herzschlag, daemon=True, name="worker-herzschlag").start()