átlagos kiegészítséek jó sok
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# /opt/docker/dev/service_finder/backend/app/workers/service_hunter.py
|
||||
# /opt/docker/dev/service_finder/backend/app/workers/service/service_robot_0_hunter.py
|
||||
import asyncio
|
||||
import httpx
|
||||
import logging
|
||||
@@ -8,7 +8,7 @@ from datetime import datetime, timezone
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy import select, text, update
|
||||
from app.db.session import AsyncSessionLocal
|
||||
from app.models.staged_data import ServiceStaging, DiscoveryParameter
|
||||
from app.models.marketplace.staged_data import ServiceStaging, DiscoveryParameter
|
||||
|
||||
# Naplózás beállítása a Sentinel monitorozáshoz
|
||||
logging.basicConfig(level=logging.INFO, format='%(asctime)s [%(levelname)s] %(name)s: %(message)s')
|
||||
@@ -119,7 +119,8 @@ class ServiceHunter:
|
||||
@classmethod
|
||||
async def run_grid_search(cls, db: AsyncSession, task: DiscoveryParameter):
|
||||
""" A város koordináta-alapú bejárása. """
|
||||
bbox = await cls._get_city_bounds(task.city, task.country_code or 'HU')
|
||||
# DiscoveryParameter modellnek nincs country_code mezője, ezért alapértelmezett 'HU'-t használunk
|
||||
bbox = await cls._get_city_bounds(task.city, 'HU')
|
||||
if not bbox:
|
||||
return
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import httpx
|
||||
from urllib.parse import quote
|
||||
from sqlalchemy import select, text
|
||||
from app.database import AsyncSessionLocal
|
||||
from app.models.service import ServiceStaging # JAVÍTOTT IMPORT ÚTVONAL!
|
||||
from app.models.marketplace.service import ServiceStaging # JAVÍTOTT IMPORT ÚTVONAL!
|
||||
import re
|
||||
|
||||
# Logolás MB 2.0 szabvány szerint
|
||||
|
||||
@@ -3,7 +3,7 @@ import logging
|
||||
import warnings
|
||||
from sqlalchemy import text, update
|
||||
from app.database import AsyncSessionLocal
|
||||
from app.models.service import ServiceStaging
|
||||
from app.models.marketplace.service import ServiceStaging
|
||||
|
||||
warnings.filterwarnings("ignore", category=RuntimeWarning, module='duckduckgo_search')
|
||||
from duckduckgo_search import DDGS
|
||||
@@ -23,8 +23,8 @@ class ServiceResearcher:
|
||||
try:
|
||||
def search():
|
||||
with DDGS() as ddgs:
|
||||
results = ddgs.text(query, max_results=3)
|
||||
return [f"- {r.get('body', '')}" for r in results] if results else []
|
||||
results = ddgs.search(query, max_results=3)
|
||||
return [f"- {r.get('body', r.get('snippet', ''))}" for r in results] if results else []
|
||||
|
||||
results = await asyncio.wait_for(asyncio.to_thread(search), timeout=self.search_timeout)
|
||||
if not results: return ""
|
||||
|
||||
@@ -1,63 +1,46 @@
|
||||
import asyncio
|
||||
import logging
|
||||
import json
|
||||
from sqlalchemy import select, text, update, func
|
||||
from app.database import AsyncSessionLocal # JAVÍTVA
|
||||
from app.models.service import ServiceProfile, ExpertiseTag, ServiceExpertise, ServiceStaging
|
||||
from sqlalchemy import select, text
|
||||
from app.database import AsyncSessionLocal
|
||||
from app.models.marketplace.service import ExpertiseTag
|
||||
|
||||
# Logolás MB 2.0 szabvány
|
||||
logging.basicConfig(level=logging.INFO, format='%(asctime)s [%(levelname)s] %(name)s: %(message)s')
|
||||
logger = logging.getLogger("Service-Robot-3-Enricher")
|
||||
|
||||
class ServiceEnricher:
|
||||
"""
|
||||
Service Robot 3: Professional Classifier (Atomi Zárolással)
|
||||
"""
|
||||
""" Service Robot 3: Professional Classifier (Bíró-Kompatibilis Verzió) """
|
||||
|
||||
@staticmethod
|
||||
async def match_expertise_to_service(db, service_profile_id: int, scraped_text: str):
|
||||
""" Kulcsszó-alapú elemző motor az ExpertiseTag tábla alapján. """
|
||||
if not scraped_text: return
|
||||
async def match_expertise_and_score(db, scraped_text: str, current_trust_score: int) -> int:
|
||||
""" Keresi a szakmákat és bónusz pontokat ad értük a Staging adatnak. """
|
||||
if not scraped_text: return current_trust_score
|
||||
|
||||
tags_query = await db.execute(select(ExpertiseTag).where(ExpertiseTag.is_official == True))
|
||||
all_tags = tags_query.scalars().all()
|
||||
|
||||
found_any = False
|
||||
match_count = 0
|
||||
for tag in all_tags:
|
||||
match_count = 0
|
||||
for kw in (tag.search_keywords or []):
|
||||
if kw.lower() in scraped_text.lower():
|
||||
match_count += 1
|
||||
|
||||
if match_count > 0:
|
||||
existing_check = await db.execute(
|
||||
select(ServiceExpertise).where(
|
||||
ServiceExpertise.service_id == service_profile_id,
|
||||
ServiceExpertise.expertise_id == tag.id
|
||||
)
|
||||
)
|
||||
|
||||
if not existing_check.scalar():
|
||||
new_link = ServiceExpertise(
|
||||
service_id=service_profile_id,
|
||||
expertise_id=tag.id,
|
||||
confidence_level=min(match_count, 2)
|
||||
)
|
||||
db.add(new_link)
|
||||
found_any = True
|
||||
logger.info(f"✅ {tag.key} szakma azonosítva a szerviznél.")
|
||||
break # Egy tag elég, ha egyszer megvan
|
||||
|
||||
if found_any:
|
||||
await db.commit()
|
||||
# +5 pont minden megtalált szakmáért, max 30 bónusz pont
|
||||
bonus = min(match_count * 5, 30)
|
||||
new_score = min(current_trust_score + bonus, 100)
|
||||
|
||||
if bonus > 0:
|
||||
logger.info(f"✅ {match_count} szakma azonosítva. Bónusz: +{bonus} pont.")
|
||||
|
||||
return new_score
|
||||
|
||||
@classmethod
|
||||
async def run_worker(cls):
|
||||
logger.info("🧠 Service Enricher ONLINE - Szakmai elemzés indítása (Atomi Zárolás)")
|
||||
logger.info("🧠 Service Enricher ONLINE - Adatdúsítás (Nem publikál, csak pontoz!)")
|
||||
|
||||
while True:
|
||||
try:
|
||||
async with AsyncSessionLocal() as db:
|
||||
# 1. Zárolunk egy "enrich_ready" szervizt a Staging táblából
|
||||
query = text("""
|
||||
UPDATE marketplace.service_staging
|
||||
SET status = 'enriching'
|
||||
@@ -67,41 +50,34 @@ class ServiceEnricher:
|
||||
FOR UPDATE SKIP LOCKED
|
||||
LIMIT 1
|
||||
)
|
||||
RETURNING id, name, city, full_address, fingerprint, raw_data;
|
||||
RETURNING id, name, trust_score, raw_data;
|
||||
""")
|
||||
result = await db.execute(query)
|
||||
task = result.fetchone()
|
||||
await db.commit()
|
||||
|
||||
if task:
|
||||
s_id, name, city, address, fprint, raw_data = task
|
||||
s_id, name, t_score, raw_data = task
|
||||
web_context = raw_data.get('web_context', '') if isinstance(raw_data, dict) else ''
|
||||
|
||||
async with AsyncSessionLocal() as process_db:
|
||||
try:
|
||||
# 2. Áttesszük a végleges ServiceProfile táblába (mert már van elég adatunk a webről)
|
||||
profile_stmt = text("""
|
||||
INSERT INTO marketplace.service_profiles
|
||||
(fingerprint, status, trust_score, location, is_verified, bio)
|
||||
VALUES (:fp, 'active', 40, ST_SetSRID(ST_MakePoint(19.04, 47.49), 4326), false, :bio)
|
||||
ON CONFLICT (fingerprint) DO UPDATE SET bio = EXCLUDED.bio
|
||||
RETURNING id;
|
||||
""") # Megjegyzés: A GPS koordinátát (19.04, 47.49) majd a Validator (Robot-4) pontosítja!
|
||||
# 1. Kiszámoljuk az új pontszámot a webes adatok (kulcsszavak) alapján
|
||||
new_score = await cls.match_expertise_and_score(process_db, web_context, t_score)
|
||||
|
||||
p_result = await process_db.execute(profile_stmt, {"fp": fprint, "bio": name + " - " + city})
|
||||
profile_id = p_result.scalar()
|
||||
await process_db.commit()
|
||||
|
||||
# 3. Futtatjuk a kulcsszó-elemzést
|
||||
await cls.match_expertise_to_service(process_db, profile_id, web_context)
|
||||
|
||||
# 4. Lezárjuk a Staging feladatot
|
||||
await process_db.execute(text("UPDATE marketplace.service_staging SET status = 'processed' WHERE id = :id"), {"id": s_id})
|
||||
# 2. Visszaírjuk a Staging táblába, és átadjuk az Auditor-nak (Gamification 2.0: auditor_ready státusz)
|
||||
upd_query = text("""
|
||||
UPDATE marketplace.service_staging
|
||||
SET status = 'auditor_ready', trust_score = :ns
|
||||
WHERE id = :id
|
||||
""")
|
||||
await process_db.execute(upd_query, {"ns": new_score, "id": s_id})
|
||||
await process_db.commit()
|
||||
logger.info(f"✅ Dúsítás kész: {name} (Pont: {t_score} -> {new_score}). Átadva az Auditor-nak (auditor_ready).")
|
||||
|
||||
except Exception as e:
|
||||
await process_db.rollback()
|
||||
logger.error(f"Hiba a dúsítás során ({s_id}): {e}")
|
||||
logger.error(f"❌ Hiba a dúsítás során ({s_id}): {e}")
|
||||
await process_db.execute(text("UPDATE marketplace.service_staging SET status = 'error' WHERE id = :id"), {"id": s_id})
|
||||
await process_db.commit()
|
||||
else:
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
# /opt/docker/dev/service_finder/backend/app/workers/service/service_robot_4_validator_google.py
|
||||
import asyncio
|
||||
import httpx
|
||||
import logging
|
||||
@@ -7,7 +8,7 @@ import json
|
||||
from datetime import datetime
|
||||
from sqlalchemy import text, update, func
|
||||
from app.database import AsyncSessionLocal
|
||||
from app.models.service import ServiceProfile
|
||||
from app.models.marketplace.service import ServiceProfile
|
||||
|
||||
logging.basicConfig(level=logging.INFO, format='%(asctime)s [%(levelname)s] Robot-4-Validator: %(message)s', stream=sys.stdout)
|
||||
logger = logging.getLogger("Service-Robot-4-Google-Validator")
|
||||
|
||||
368
backend/app/workers/service/service_robot_5_auditor.py
Normal file
368
backend/app/workers/service/service_robot_5_auditor.py
Normal file
@@ -0,0 +1,368 @@
|
||||
# /opt/docker/dev/service_finder/backend/app/workers/service/service_robot_5_auditor.py
|
||||
import asyncio
|
||||
import logging
|
||||
import json
|
||||
import random
|
||||
from datetime import datetime
|
||||
from sqlalchemy import select, text, update, insert
|
||||
from sqlalchemy.dialects.postgresql import insert as pg_insert
|
||||
from app.database import AsyncSessionLocal
|
||||
|
||||
# MB 2.0: Közvetlen és teljes importok a hiánytalan működéshez
|
||||
from app.models.marketplace.service import ServiceStaging, ServiceProfile, ExpertiseTag, ServiceExpertise
|
||||
from app.models.marketplace.organization import Organization
|
||||
from app.models.identity.identity import User, Person
|
||||
from app.models.gamification.gamification import UserContribution, PointsLedger, UserStats
|
||||
from app.models.system.system import SystemParameter
|
||||
from app.core.config import settings
|
||||
|
||||
# --- NAPLÓZÁS KONFIGURÁCIÓ ---
|
||||
logging.basicConfig(level=logging.INFO, format='%(asctime)s [%(levelname)s] Service-Robot-5-Auditor: %(message)s')
|
||||
logger = logging.getLogger("Service-Robot-5-Auditor")
|
||||
|
||||
class ServiceAuditor:
|
||||
"""
|
||||
Service Robot 5: Auditor és Publikáló (Staging → Production)
|
||||
Verzió: 1.3 - Tömörítetlen, teljes adatstruktúra szinkronnal és ADAPTÍV időzítéssel.
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
async def get_trust_threshold(db) -> int:
|
||||
""" Lekéri a SystemParameter-ből a trust score küszöböt a validáláshoz. """
|
||||
try:
|
||||
query = select(SystemParameter).where(
|
||||
SystemParameter.key == "service_trust_threshold"
|
||||
)
|
||||
result = await db.execute(query)
|
||||
param = result.scalar_one_or_none()
|
||||
|
||||
if param and param.value:
|
||||
logger.info(f"🔍 Rendszer trust küszöb értéke: {param.value}")
|
||||
return int(param.value)
|
||||
except Exception as e:
|
||||
logger.warning(f"⚠️ Trust threshold lekérdezés hiba, alapértelmezett 70 használata: {e}")
|
||||
|
||||
return 70
|
||||
|
||||
@staticmethod
|
||||
async def create_digital_twin(db, staging_data: dict) -> int:
|
||||
"""
|
||||
Létrehoz vagy megkeres egy Digital Twin (Organization) entitást.
|
||||
A 'fleet' sémában lévő organizations táblát kezeli.
|
||||
"""
|
||||
try:
|
||||
tax_no = staging_data.get("tax_number")
|
||||
org_name = staging_data.get("name", "").strip()
|
||||
existing_org = None
|
||||
|
||||
# 1. Ellenőrzés adószám alapján (ha rendelkezésre áll)
|
||||
if tax_no:
|
||||
logger.info(f"🔎 Digital Twin keresése adószám alapján: {tax_no}")
|
||||
tax_query = select(Organization).where(
|
||||
Organization.tax_number == tax_no.strip(),
|
||||
Organization.is_deleted == False
|
||||
)
|
||||
tax_result = await db.execute(tax_query)
|
||||
existing_org = tax_result.scalar_one_or_none()
|
||||
|
||||
# 2. Ellenőrzés név alapján (ha az adószám nem talált egyezést)
|
||||
if not existing_org and org_name:
|
||||
logger.info(f"🔎 Digital Twin keresése név alapján: {org_name}")
|
||||
org_query = select(Organization).where(
|
||||
Organization.name == org_name,
|
||||
Organization.is_deleted == False
|
||||
)
|
||||
name_result = await db.execute(org_query)
|
||||
existing_org = name_result.scalar_one_or_none()
|
||||
|
||||
if existing_org:
|
||||
logger.info(f"✅ Meglévő Digital Twin azonosítva: {existing_org.name} (ID: {existing_org.id})")
|
||||
return existing_org.id
|
||||
|
||||
# 3. Új Organization (Digital Twin) létrehozása
|
||||
new_org = Organization(
|
||||
name=org_name,
|
||||
full_name=staging_data.get("full_name") or org_name,
|
||||
tax_number=tax_no,
|
||||
reg_number=staging_data.get("registration_number"),
|
||||
contact_email=staging_data.get("contact_email"),
|
||||
contact_phone=staging_data.get("contact_phone"),
|
||||
website=staging_data.get("website"),
|
||||
address_zip=staging_data.get("postal_code"),
|
||||
address_city=staging_data.get("city"),
|
||||
address_street_name=staging_data.get("address_line1"),
|
||||
country_code=staging_data.get("country_code", "HU"),
|
||||
is_active=True,
|
||||
status="active",
|
||||
created_at=datetime.utcnow(),
|
||||
updated_at=datetime.utcnow()
|
||||
)
|
||||
|
||||
db.add(new_org)
|
||||
await db.flush()
|
||||
await db.refresh(new_org)
|
||||
|
||||
logger.info(f"✨ Új Digital Twin (Organization) létrehozva: {new_org.name}")
|
||||
return new_org.id
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Digital Twin hiba: {e}")
|
||||
raise
|
||||
|
||||
@staticmethod
|
||||
async def create_service_profile(db, staging_data: dict, org_id: int) -> int:
|
||||
""" Létrehozza az éles ServiceProfile rekordot a marketplace sémában. """
|
||||
try:
|
||||
new_service = ServiceProfile(
|
||||
organization_id=org_id,
|
||||
name=staging_data.get("name", "").strip(),
|
||||
description=staging_data.get("description") or "",
|
||||
contact_email=staging_data.get("contact_email"),
|
||||
contact_phone=staging_data.get("contact_phone"),
|
||||
website=staging_data.get("website"),
|
||||
address_line1=staging_data.get("address_line1"),
|
||||
address_line2=staging_data.get("address_line2"),
|
||||
city=staging_data.get("city"),
|
||||
postal_code=staging_data.get("postal_code"),
|
||||
country_code=staging_data.get("country_code", "HU"),
|
||||
latitude=staging_data.get("latitude"),
|
||||
longitude=staging_data.get("longitude"),
|
||||
trust_score=staging_data.get("trust_score", 0),
|
||||
status="active",
|
||||
external_id=staging_data.get("external_id"),
|
||||
metadata=staging_data.get("metadata") or {},
|
||||
created_at=datetime.utcnow(),
|
||||
updated_at=datetime.utcnow()
|
||||
)
|
||||
|
||||
db.add(new_service)
|
||||
await db.flush()
|
||||
await db.refresh(new_service)
|
||||
|
||||
logger.info(f"✅ Éles ServiceProfile rögzítve: {new_service.name} (ID: {new_service.id})")
|
||||
return new_service.id
|
||||
except Exception as e:
|
||||
logger.error(f"❌ ServiceProfile rögzítési hiba: {e}")
|
||||
raise
|
||||
|
||||
@staticmethod
|
||||
async def award_user_contribution(db, user_id: int, service_id: int, staging_id: int):
|
||||
""" XP és pontok kiosztása a felhasználónak. """
|
||||
try:
|
||||
# 1. Aktuális aktív szezon keresése
|
||||
season_query = text("""
|
||||
SELECT id FROM system.seasons
|
||||
WHERE is_active = true
|
||||
AND start_date <= CURRENT_DATE
|
||||
AND end_date >= CURRENT_DATE
|
||||
LIMIT 1
|
||||
""")
|
||||
result = await db.execute(season_query)
|
||||
season_row = result.fetchone()
|
||||
season_id = season_row[0] if season_row else None
|
||||
|
||||
# 2. UserContribution rekord létrehozása
|
||||
contribution = UserContribution(
|
||||
user_id=user_id,
|
||||
season_id=season_id,
|
||||
contribution_type="service_submission",
|
||||
entity_type="service",
|
||||
entity_id=service_id,
|
||||
points_awarded=50,
|
||||
xp_awarded=100,
|
||||
status="approved",
|
||||
metadata={
|
||||
"staging_id": staging_id,
|
||||
"awarded_at": datetime.utcnow().isoformat(),
|
||||
"reason": "Auditor publication approval"
|
||||
},
|
||||
created_at=datetime.utcnow()
|
||||
)
|
||||
db.add(contribution)
|
||||
|
||||
# 3. UserStats (globális statisztika) frissítése
|
||||
stats_query = select(UserStats).where(UserStats.user_id == user_id)
|
||||
stats_result = await db.execute(stats_query)
|
||||
user_stats = stats_result.scalar_one_or_none()
|
||||
|
||||
if user_stats:
|
||||
user_stats.total_points += 50
|
||||
user_stats.total_xp += 100
|
||||
user_stats.services_submitted += 1
|
||||
user_stats.updated_at = datetime.utcnow()
|
||||
else:
|
||||
new_stats = UserStats(
|
||||
user_id=user_id, total_points=50, total_xp=100,
|
||||
services_submitted=1, created_at=datetime.utcnow()
|
||||
)
|
||||
db.add(new_stats)
|
||||
|
||||
# 4. PointsLedger bejegyzés
|
||||
ledger = PointsLedger(
|
||||
user_id=user_id, points=50, xp=100,
|
||||
source_type="service_submission",
|
||||
source_id=service_id,
|
||||
description="Reward for verified service publication",
|
||||
created_at=datetime.utcnow()
|
||||
)
|
||||
db.add(ledger)
|
||||
|
||||
logger.info(f"🏆 Jutalmazás elvégezve: User {user_id} (+50 PT, +100 XP)")
|
||||
except Exception as e:
|
||||
logger.error(f"⚠️ Hiba a jutalmazási folyamatban: {e}")
|
||||
|
||||
@classmethod
|
||||
async def process_staging_record(cls, db, staging_id: int):
|
||||
""" Egyetlen staging rekord teljes körű feldolgozása tranzakcióban. """
|
||||
try:
|
||||
# 1. Rekord lekérése
|
||||
query = select(ServiceStaging).where(
|
||||
ServiceStaging.id == staging_id,
|
||||
ServiceStaging.status == 'auditing'
|
||||
)
|
||||
result = await db.execute(query)
|
||||
staging = result.scalar_one_or_none()
|
||||
|
||||
if not staging:
|
||||
logger.error(f"❌ Staging rekord nem található vagy rossz státuszban van: {staging_id}")
|
||||
return False
|
||||
|
||||
# 2. Trust Score ellenőrzés
|
||||
trust_threshold = await cls.get_trust_threshold(db)
|
||||
if staging.trust_score < trust_threshold:
|
||||
logger.warning(f"🚫 Trust Score elégtelen: {staging.trust_score} < {trust_threshold}")
|
||||
staging.status = 'rejected'
|
||||
staging.rejection_reason = f'Low trust score ({staging.trust_score})'
|
||||
staging.updated_at = datetime.utcnow()
|
||||
await db.commit()
|
||||
return False
|
||||
|
||||
# 3. Adatok kigyűjtése explicit módon
|
||||
staging_data = {
|
||||
"name": staging.name,
|
||||
"description": staging.description,
|
||||
"contact_email": staging.contact_email,
|
||||
"contact_phone": staging.contact_phone,
|
||||
"website": staging.website,
|
||||
"address_line1": staging.address_line1,
|
||||
"address_line2": staging.address_line2,
|
||||
"city": staging.city,
|
||||
"postal_code": staging.postal_code,
|
||||
"country_code": staging.country_code,
|
||||
"latitude": staging.latitude,
|
||||
"longitude": staging.longitude,
|
||||
"trust_score": staging.trust_score,
|
||||
"external_id": staging.external_id,
|
||||
"metadata": staging.metadata or {},
|
||||
"tax_number": staging.metadata.get("tax_number") if staging.metadata else None,
|
||||
"registration_number": staging.metadata.get("registration_number") if staging.metadata else None
|
||||
}
|
||||
|
||||
# 4. Digital Twin (Cég) fázis
|
||||
org_id = await cls.create_digital_twin(db, staging_data)
|
||||
|
||||
# 5. Production (Szolgáltatás) fázis
|
||||
service_id = await cls.create_service_profile(db, staging_data, org_id)
|
||||
|
||||
# 6. Gamification fázis
|
||||
if staging.submitted_by:
|
||||
await cls.award_user_contribution(db, staging.submitted_by, service_id, staging_id)
|
||||
|
||||
# 7. Lezárás és Audit Trail mentése
|
||||
staging.status = 'published'
|
||||
staging.published_at = datetime.utcnow()
|
||||
staging.service_profile_id = service_id
|
||||
staging.organization_id = org_id
|
||||
staging.updated_at = datetime.utcnow()
|
||||
staging.audit_trail = {
|
||||
"audited_by": "robot_5",
|
||||
"audited_at": datetime.utcnow().isoformat(),
|
||||
"trust_threshold_used": trust_threshold,
|
||||
"final_trust_score": staging.trust_score,
|
||||
"organization_id": org_id,
|
||||
"service_profile_id": service_id,
|
||||
"version": "1.3"
|
||||
}
|
||||
|
||||
await db.commit()
|
||||
logger.info(f"✅ SIKER: Staging {staging_id} -> Production {service_id}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Kritikus feldolgozási hiba (Staging ID: {staging_id}): {e}")
|
||||
await db.rollback()
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def run_worker(cls):
|
||||
"""
|
||||
Az Auditor fő folyamata:
|
||||
Adaptív ciklus: 20mp ha van adat, 5 perc ha 5x üres.
|
||||
"""
|
||||
logger.info("🚀 Service Auditor v1.3 ONLINE - Adaptív üzemmód")
|
||||
empty_counter = 0
|
||||
|
||||
while True:
|
||||
try:
|
||||
async with AsyncSessionLocal() as db:
|
||||
# 1. Következő rekord lefoglalása atomi módon
|
||||
query = text("""
|
||||
UPDATE marketplace.service_staging
|
||||
SET status = 'auditing'
|
||||
WHERE id = (
|
||||
SELECT id FROM marketplace.service_staging
|
||||
WHERE status = 'auditor_ready'
|
||||
AND trust_score >= (
|
||||
SELECT COALESCE(
|
||||
(SELECT value::integer FROM system.system_parameters
|
||||
WHERE key = 'service_trust_threshold'),
|
||||
70
|
||||
)
|
||||
)
|
||||
FOR UPDATE SKIP LOCKED
|
||||
LIMIT 1
|
||||
)
|
||||
RETURNING id
|
||||
""")
|
||||
|
||||
result = await db.execute(query)
|
||||
row = result.fetchone()
|
||||
|
||||
if not row:
|
||||
empty_counter += 1
|
||||
if empty_counter >= 5:
|
||||
sleep_time = 600 # 5 perc várakozás
|
||||
logger.info(f"💤 Nincs adat (5x üres). Lassítás {sleep_time} másodpercre (5 perc)...")
|
||||
else:
|
||||
sleep_time = 20 # 20 másodperc várakozás
|
||||
logger.info(f"⏳ Várólista üres, következő próba {sleep_time} mp múlva. (Próba: {empty_counter}/5)")
|
||||
|
||||
await db.commit()
|
||||
await asyncio.sleep(sleep_time)
|
||||
continue
|
||||
|
||||
# Ha találtunk adatot:
|
||||
empty_counter = 0
|
||||
staging_id = row[0]
|
||||
await db.commit() # Elengedjük a zárolást a hosszas feldolgozáshoz
|
||||
|
||||
logger.info(f"🎯 Auditor feldolgozás indítása: staging_id={staging_id}")
|
||||
|
||||
# 2. Rekord tényleges feldolgozása egy friss session-ben
|
||||
async with AsyncSessionLocal() as process_db:
|
||||
await cls.process_staging_record(process_db, staging_id)
|
||||
|
||||
# 3. Sikeres feldolgozás utáni pihenő az utasítás szerint (20 mp)
|
||||
await asyncio.sleep(20)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Auditor fő ciklus hiba: {e}")
|
||||
await asyncio.sleep(10)
|
||||
|
||||
async def main():
|
||||
""" Belépési pont a konténer számára. """
|
||||
auditor = ServiceAuditor()
|
||||
await auditor.run_worker()
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
Reference in New Issue
Block a user