Deploy grok2api (jiujiu532) to HF Space: port 7860, bucket persistence at /app/data
48d895c verified | """Proxy clearance refresh scheduler. | |
| Periodically refreshes ClearanceBundles for managed (FlareSolverr) mode. | |
| Previously inline in ProxyDirectory; extracted for separation of concerns. | |
| """ | |
| import asyncio | |
| from app.platform.logging.logger import logger | |
| from app.platform.config.snapshot import get_config | |
| from app.control.proxy import ProxyDirectory | |
| class ProxyClearanceScheduler: | |
| """Periodically refreshes proxy clearance bundles.""" | |
| def __init__(self, directory: ProxyDirectory) -> None: | |
| self._directory = directory | |
| self._task: asyncio.Task | None = None | |
| self._running = False | |
| def start(self) -> None: | |
| if self._running: | |
| return | |
| self._running = True | |
| self._task = asyncio.create_task(self._loop()) | |
| logger.info("proxy clearance scheduler started") | |
| def stop(self) -> None: | |
| self._running = False | |
| if self._task and not self._task.done(): | |
| self._task.cancel() | |
| logger.info("proxy clearance scheduler stopped") | |
| async def _loop(self) -> None: | |
| # Warm up immediately on start so the first request doesn't block. | |
| await self._warm_up() | |
| while self._running: | |
| try: | |
| interval = self._get_interval() | |
| await asyncio.sleep(interval) | |
| if not self._running: | |
| break | |
| await self._refresh() | |
| except asyncio.CancelledError: | |
| break | |
| except Exception as exc: | |
| logger.error( | |
| "proxy clearance scheduler loop failed: error_type={} error={}", | |
| type(exc).__name__, | |
| exc, | |
| ) | |
| await asyncio.sleep(60) | |
| async def _warm_up(self) -> None: | |
| """Pre-fetch clearance bundles without invalidating existing ones.""" | |
| try: | |
| await self._directory.load() | |
| await self._directory.warm_up() | |
| logger.debug("proxy clearance warm-up completed") | |
| except Exception as exc: | |
| logger.warning("proxy clearance warm-up failed: error={}", exc) | |
| async def _refresh(self) -> None: | |
| """Build fresh clearance bundles and swap atomically (build-then-swap). | |
| Old bundles are kept if FlareSolverr is unavailable, so a transient | |
| refresh failure never leaves requests without clearance. | |
| """ | |
| try: | |
| await self._directory.load() | |
| await self._directory.refresh_clearance_safe() | |
| logger.debug("proxy clearance refresh completed") | |
| except Exception as exc: | |
| logger.warning("proxy clearance refresh failed: error={}", exc) | |
| def _get_interval(self) -> int: | |
| """Return refresh interval in seconds from config.""" | |
| cfg = get_config() | |
| return cfg.get_int("proxy.clearance.refresh_interval", 600) | |
| __all__ = ["ProxyClearanceScheduler"] | |