"""ASV benchmarks for CONC3 cleanup service throughput. Measures the performance of scan and purge operations to ensure cleanup overhead stays within acceptable bounds. """ from __future__ import annotations import importlib import sys import tempfile from pathlib import Path # Ensure the local *source* tree is importable. _SRC = str(Path(__file__).resolve().parents[1] / "src") if _SRC not in sys.path: sys.path.insert(0, _SRC) import cleveragents # noqa: E402 importlib.reload(cleveragents) from datetime import UTC # noqa: E402 from cleveragents.application.services.cleanup_service import ( # noqa: E402 CleanupService, ) from cleveragents.config.settings import Settings # noqa: E402 def _make_settings(**overrides: object) -> Settings: """Create Settings with overrides.""" Settings._instance = None settings = Settings() for key, value in overrides.items(): setattr(settings, key, value) return settings class ScanBenchmark: """Benchmark cleanup scan operations.""" def setup(self) -> None: self.settings = _make_settings(cleanup_sandbox_max_age_hours=48) self.service = CleanupService( settings=self.settings, active_plan_ids=frozenset(), ) def time_scan_empty(self) -> None: """Scan with no stale resources.""" self.service.scan() class CheckpointBenchmark: """Benchmark checkpoint scanning and pruning.""" def setup(self) -> None: self.settings = _make_settings(cleanup_checkpoint_max_per_plan=50) self.service = CleanupService( settings=self.settings, active_plan_ids=frozenset(), ) self.checkpoint_dir = Path( tempfile.mkdtemp(prefix="ca-bench-checkpoint-"), ) for i in range(100): f = self.checkpoint_dir / f"checkpoint_{i:04d}.json" f.write_text(f'{{"step": {i}}}') def teardown(self) -> None: import shutil shutil.rmtree(self.checkpoint_dir, ignore_errors=True) def time_scan_checkpoints(self) -> None: self.service.scan_checkpoints_for_plan(self.checkpoint_dir) def time_prune_checkpoints(self) -> None: self.service.prune_checkpoints_for_plan(self.checkpoint_dir) class SessionScanBenchmark: """Benchmark session inactivity scanning.""" def setup(self) -> None: from datetime import datetime, timedelta self.settings = _make_settings( cleanup_session_inactivity_days=30, ) self.service = CleanupService( settings=self.settings, active_plan_ids=frozenset(), ) now = datetime.now(tz=UTC) self.sessions = [ { "session_id": f"sess-{i:04d}", "updated_at": now - timedelta(days=i), } for i in range(100) ] def time_scan_sessions(self) -> None: self.service.scan_inactive_sessions(self.sessions)