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 import zombies # noqa: E402 @worker_ready.connect def raeume_job_leichen_auf(**kwargs): """Nach der Gnadenfrist: Jobs, an denen niemand arbeitet, ehrlich auf 'failed' setzen (Details und Sicherungen in zombies.py). Läuft im Hintergrund-Thread — der Worker soll sofort Aufgaben annehmen und nicht zwei Minuten auf die Aufräumung warten. """ import threading import time def spaeter(): time.sleep(zombies.GNADENFRIST_SEKUNDEN) try: db.init_db() bericht = zombies.raeume_zombies_auf(celery_app, db) print(f"Zombie-Erkennung: {bericht}") except Exception as e: # darf den Worker nie mitnehmen print(f"Zombie-Erkennung fehlgeschlagen: {e}") threading.Thread(target=spaeter, daemon=True, name="zombie-erkennung").start() @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()