"""ASV benchmarks for retry policy overhead measurement. Measures the cost of: - RetryPolicyConfig construction and validation - CircuitBreakerConfig construction - ServiceRetryPolicyRegistry lookup and override application - ServiceRetryWiring.execute() overhead (happy path, no actual retries) - CircuitBreaker call() overhead in closed state - retry_service_operation decorator overhead Based on issue #313 (feat(async): wire retry policies into services). """ from __future__ import annotations import os import sys # Ensure the source is on the path for ASV sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "src")) class TimeRetryPolicyConfigCreation: """Benchmark RetryPolicyConfig default construction.""" timeout = 60.0 def setup(self) -> None: from cleveragents.domain.models.core.retry_policy import RetryPolicyConfig self.cls = RetryPolicyConfig def time_default_construction(self) -> None: self.cls() def time_custom_construction(self) -> None: self.cls( max_attempts=5, base_delay=2.0, max_delay=30.0, jitter=True, backoff_strategy="exponential", ) class TimeCircuitBreakerConfigCreation: """Benchmark CircuitBreakerConfig construction.""" timeout = 60.0 def setup(self) -> None: from cleveragents.domain.models.core.retry_policy import CircuitBreakerConfig self.cls = CircuitBreakerConfig def time_default_construction(self) -> None: self.cls() class TimeServiceRetryPolicyRegistryLookup: """Benchmark ServiceRetryPolicyRegistry get() performance.""" timeout = 60.0 def setup(self) -> None: from cleveragents.domain.models.core.retry_policy import ( ServiceRetryPolicyRegistry, ) self.registry = ServiceRetryPolicyRegistry() def time_known_service_lookup(self) -> None: self.registry.get("plan_service") def time_unknown_service_lookup(self) -> None: self.registry.get("unknown_service_xyz") def time_apply_overrides(self) -> None: self.registry.apply_overrides({"plan_service": {"retry": {"max_attempts": 5}}}) class TimeServiceRetryWiringExecute: """Benchmark ServiceRetryWiring.execute() happy-path overhead.""" timeout = 60.0 def setup(self) -> None: os.environ.setdefault("CLEVERAGENTS_ENV", "test") os.environ.setdefault("CLEVERAGENTS_MOCK_PROVIDERS", "true") from cleveragents.application.services.service_retry_wiring import ( ServiceRetryWiring, ) from cleveragents.config.settings import Settings settings = Settings( database_url="sqlite:///bench_retry.db", mock_providers=True, env="test", ) self.wiring = ServiceRetryWiring(settings) def time_execute_idempotent_success(self) -> None: """Measure overhead of a successful idempotent call through wiring.""" self.wiring.execute( service_name="plan_service", operation_name="bench_op", func=lambda: 42, idempotent=True, ) def time_execute_non_idempotent(self) -> None: """Measure overhead of a non-idempotent call (no retry wrapper).""" self.wiring.execute( service_name="plan_service", operation_name="bench_write", func=lambda: 42, idempotent=False, ) class TimeCircuitBreakerCallOverhead: """Benchmark CircuitBreaker.call() in closed state.""" timeout = 60.0 def setup(self) -> None: from cleveragents.core.retry_patterns import CircuitBreaker self.cb = CircuitBreaker(failure_threshold=5, recovery_timeout=60.0) def time_successful_call(self) -> None: self.cb.call(lambda: 42)