"""ASV benchmarks for session create service-layer performance (bug #570). Measures the cost of creating a session through ``PersistentSessionService`` using a file-based SQLite database so that each operation exercises the full service layer (repository -> SQLAlchemy -> SQLite round-trip). Note: these benchmarks construct ``PersistentSessionService`` directly and do **not** exercise the DI container wiring path (``_get_session_service`` / ``container.db()``). Their purpose is to establish a service-layer create performance baseline so regressions can be detected after the bug-fix lands. Same root cause as bug #554. """ from __future__ import annotations import importlib import os import shutil import sys import tempfile from pathlib import Path _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 sqlalchemy import create_engine # noqa: E402 from sqlalchemy.orm import sessionmaker # noqa: E402 from cleveragents.application.services.session_service import ( # noqa: E402 PersistentSessionService, ) from cleveragents.infrastructure.database.models import Base # noqa: E402 from cleveragents.infrastructure.database.repositories import ( # noqa: E402 SessionMessageRepository, SessionRepository, ) class SessionCreateDISuite: """Benchmark session create through the service layer. Engine and sessionmaker are built once in ``setup()`` and reused across benchmark iterations to measure service-layer cost without engine construction overhead. """ timeout = 60 def setup(self) -> None: self._tmpdir = tempfile.mkdtemp(prefix="bench_sce_570_") self._db_path = os.path.join(self._tmpdir, "bench.db") self._engine = create_engine(f"sqlite:///{self._db_path}", echo=False) Base.metadata.create_all(self._engine) self._session_factory = sessionmaker(bind=self._engine, expire_on_commit=False) def teardown(self) -> None: self._engine.dispose() shutil.rmtree(self._tmpdir, ignore_errors=True) def _make_service(self) -> PersistentSessionService: """Build a PersistentSessionService using the shared session factory.""" return PersistentSessionService( session_repo=SessionRepository(session_factory=self._session_factory), message_repo=SessionMessageRepository( session_factory=self._session_factory ), ) def time_create_session(self) -> None: """Create a session via the service layer.""" svc = self._make_service() svc.create() def time_create_with_actor(self) -> None: """Create a session with a custom actor.""" svc = self._make_service() svc.create(actor_name="openai/gpt-4") def track_create_persists(self) -> int: """Track session create persistence at the service layer. Returns the count of sessions created via the service. This benchmark constructs ``PersistentSessionService`` directly, bypassing the DI container (``_get_session_service`` / ``container.db()``). It therefore does **not** reproduce bug #570 — its purpose is to establish a service-layer persistence baseline so regressions can be detected after the fix lands. """ svc = self._make_service() svc.create(actor_name="bench/create-test") sessions = svc.list() return len(sessions) SessionCreateDISuite.track_create_persists.unit = "sessions"