# /opt/docker/dev/service_finder/backend/app/workers/service_auditor.py import asyncio import logging from datetime import datetime, timezone from sqlalchemy import select, and_ from app.db.session import AsyncSessionLocal from app.models.organization import Organization, OrgType from app.models.service import ServiceProfile # Logolás beállítása a Sentinel rendszerhez logging.basicConfig(level=logging.INFO, format='%(asctime)s [%(levelname)s]: %(message)s') logger = logging.getLogger("Robot-Service-Auditor") class ServiceAuditor: """ Robot: Service Auditor. Feladata a meglévő szerviz szolgáltatók adatainak validálása és a megszűnt helyek inaktiválása. """ @classmethod async def audit_services(cls): """ Időszakos ellenőrzés a megszűnt helyek kiszűrésére. """ async with AsyncSessionLocal() as db: # 1. LOGIKA: Csak az aktív szerviz típusú szervezeteket keressük stmt = select(Organization).where( and_( Organization.org_type == OrgType.service, Organization.is_active == True ) ) result = await db.execute(stmt) services = result.scalars().all() logger.info(f"🕵️ Audit indítása {len(services)} szerviznél...") for service in services: try: # 2. LOGIKA: Ellenőrzés külső forrásnál (API hívás OSM/Google/Cégtár felé) # Itt futhat le egy külső keresés a név és cím alapján. # Példa: status = await external_api.is_still_operating(service.id) is_still_open = True # Ez a szimulált API válasz # 3. LOGIKA: MDM Frissítés stmt_profile = select(ServiceProfile).where(ServiceProfile.organization_id == service.id) profile_res = await db.execute(stmt_profile) profile = profile_res.scalar_one_or_none() if not is_still_open: # Soft-delete: a szervezet inaktív lesz, a profil státusza bezárt service.is_active = False if profile: profile.status = 'closed' profile.last_audit_at = datetime.now(timezone.utc) logger.info(f"⚠️ Szerviz inaktiválva (megszűnt): {service.full_name}") else: # Ha nyitva van, csak az audit dátumát frissítjük if profile: profile.last_audit_at = datetime.now(timezone.utc) # 4. Rate limit védelem a külső API-k és a DB terhelés kímélése érdekében await asyncio.sleep(1) except Exception as e: logger.error(f"❌ Hiba a(z) {service.full_name} auditálása közben: {str(e)}") # A tranzakció lezárása await db.commit() logger.info("✅ Szerviz-audit folyamat befejeződött.") @classmethod async def run_periodic_audit(cls): """ Folyamatos futtatás (Service mode). """ while True: try: # Alapértelmezett futási ciklus (pl. 90 naponta) await cls.audit_services() logger.info("💤 Auditor robot pihenőre tér (90 nap).") await asyncio.sleep(90 * 86400) except Exception as e: logger.error(f"🚨 Kritikus hiba az Auditor robotban: {e}") await asyncio.sleep(3600) # Hiba esetén 1 óra múlva újrapróbálja if __name__ == "__main__": asyncio.run(ServiceAuditor.run_periodic_audit())