"""Batch-flush script execution live state from Redis to MySQL (every 60s, up to 50 rows/cycle).""" import asyncio import logging from server.domain.models import AuditLog from server.infrastructure.database.audit_log_repo import AuditLogRepositoryImpl from server.infrastructure.database.script_repo import ScriptExecutionRepositoryImpl from server.infrastructure.database.session import AsyncSessionLocal from server.infrastructure.redis.script_execution_store import ( FLUSH_INTERVAL_SECONDS, detect_stuck_executions, flush_pending_batch, ) logger = logging.getLogger("nexus.script_execution_flush") async def script_execution_flush_loop(): """Every minute: flush queued script execution snapshots to MySQL.""" logger.info("Script execution flush loop started (interval=%ss)", FLUSH_INTERVAL_SECONDS) while True: await asyncio.sleep(FLUSH_INTERVAL_SECONDS) try: async with AsyncSessionLocal() as session: repo = ScriptExecutionRepositoryImpl(session) audit_repo = AuditLogRepositoryImpl(session) async def _audit(action, target_type, target_id, operator, _repo=audit_repo): # noqa: B023 await _repo.create(AuditLog( admin_username=operator or "system", action=action, target_type=target_type, target_id=target_id, detail=f"执行ID={target_id}", )) stuck = await detect_stuck_executions(repo, _audit) count = await flush_pending_batch(repo) if stuck: logger.info("Script execution: auto-marked %s stuck", stuck) if count: logger.info("Script execution flush: %s record(s) written to MySQL", count) except Exception as e: logger.error("Script execution flush loop error: %s", e)