from __future__ import annotations import asyncio from typing import List, Optional from ..common.binding import BindingManager from ..common.collection import DataCollection from ..common.persistence_service import PersistenceService, ScopedPersistenceView class ProjectScopeRuntime: """Thin runtime container for one scope execution.""" def __init__( self, *, scope: str, persistence_service: PersistenceService, persistence_view: ScopedPersistenceView, local_collection: DataCollection, remote_collection: DataCollection, binding_manager: BindingManager, local_datasource, remote_datasource, global_runtime: Optional["ProjectScopeRuntime"] = None, owns_persistence_service: bool = False, ) -> None: self.scope = scope self.persistence_service = persistence_service self.persistence_view = persistence_view self.local_collection = local_collection self.remote_collection = remote_collection self.binding_manager = binding_manager self.local_datasource = local_datasource self.remote_datasource = remote_datasource self.global_runtime = global_runtime self.owns_persistence_service = owns_persistence_service self._closed = False @property def persistence_backend(self): return self.persistence_service.backend async def load( self, *, node_types: List[str], bootstrap_binding_node_types: Optional[List[str]] = None, enable_persistence: bool = True, ephemeral_node_types: Optional[List[str]] = None, ) -> None: if not enable_persistence: return excluded_node_types = list(dict.fromkeys(ephemeral_node_types or [])) or None await self.local_collection.load_from_persistence_excluding(excluded_node_types) await self.remote_collection.load_from_persistence_excluding(excluded_node_types) excluded = set(ephemeral_node_types or []) binding_node_types = [ node_type for node_type in dict.fromkeys([*node_types, *(bootstrap_binding_node_types or [])]) if node_type not in excluded ] for node_type in binding_node_types: await self.binding_manager.load_from_persistence(node_type) async def persist( self, *, enable_persistence: bool = True, ephemeral_node_types: Optional[List[str]] = None, ) -> None: if not enable_persistence: return await self.local_collection.persist(exclude_node_types=ephemeral_node_types) await self.remote_collection.persist(exclude_node_types=ephemeral_node_types) await self.binding_manager.persist(exclude_node_types=ephemeral_node_types) async def unload(self) -> None: await self.local_collection.unload() await self.remote_collection.unload() await self.binding_manager.unload() async def close(self) -> None: if self._closed: return self._closed = True await self._safe_close("remote_datasource", self.remote_datasource.close()) await self._safe_close("local_datasource", self.local_datasource.close()) if self.owns_persistence_service: await self._safe_close("persistence_service", self.persistence_service.close()) async def _safe_close(self, name: str, close_coro, timeout: float = 3.0) -> None: try: await asyncio.wait_for(close_coro, timeout=timeout) except asyncio.TimeoutError: return except Exception: return