fix(agent): stabilize live e2e tool execution and loop isolation
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import inspect
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
@@ -15,6 +16,7 @@ class RedisService(BaseServiceProvider):
|
||||
super().__init__("redis")
|
||||
self._settings = settings or config.redis
|
||||
self._client: Optional[redis.Redis] = None
|
||||
self._loop_id: int | None = None
|
||||
|
||||
def _build_client(self) -> redis.Redis:
|
||||
return redis.from_url(
|
||||
@@ -38,28 +40,33 @@ class RedisService(BaseServiceProvider):
|
||||
if inspect.isawaitable(ping_result):
|
||||
await ping_result
|
||||
self._client = client
|
||||
self._loop_id = _current_loop_id()
|
||||
self._set_initialized(True)
|
||||
self.logger.info("Redis service initialized")
|
||||
return True
|
||||
except Exception as exc: # noqa: BLE001
|
||||
self.logger.warning("Redis service initialization failed", error=str(exc))
|
||||
self._client = None
|
||||
self._loop_id = None
|
||||
self._set_initialized(False)
|
||||
return False
|
||||
|
||||
async def close(self) -> bool:
|
||||
client = self._client
|
||||
if client is None:
|
||||
self._loop_id = None
|
||||
return True
|
||||
try:
|
||||
await client.aclose()
|
||||
self.logger.info("Redis service closed")
|
||||
self._client = None
|
||||
self._set_initialized(False)
|
||||
return True
|
||||
except Exception as exc: # noqa: BLE001
|
||||
self.logger.exception("Redis service close failed", error=str(exc))
|
||||
return False
|
||||
finally:
|
||||
self._client = None
|
||||
self._loop_id = None
|
||||
self._set_initialized(False)
|
||||
|
||||
async def health_check(self) -> Dict[str, Any]:
|
||||
client = self._client
|
||||
@@ -92,7 +99,31 @@ class RedisService(BaseServiceProvider):
|
||||
return self._require_client()
|
||||
|
||||
|
||||
def _current_loop_id() -> int | None:
|
||||
try:
|
||||
return id(asyncio.get_running_loop())
|
||||
except RuntimeError:
|
||||
return None
|
||||
|
||||
|
||||
async def get_or_init_redis_client() -> redis.Redis:
|
||||
current_loop_id = _current_loop_id()
|
||||
bound_loop_id = redis_service._loop_id
|
||||
if (
|
||||
redis_service.is_initialized
|
||||
and bound_loop_id is not None
|
||||
and current_loop_id is not None
|
||||
and bound_loop_id != current_loop_id
|
||||
):
|
||||
redis_service.logger.warning(
|
||||
"Redis client bound to different event loop; reinitializing",
|
||||
previous_loop_id=bound_loop_id,
|
||||
current_loop_id=current_loop_id,
|
||||
)
|
||||
redis_service._client = None
|
||||
redis_service._loop_id = None
|
||||
redis_service._set_initialized(False)
|
||||
|
||||
if not redis_service.is_initialized:
|
||||
initialized = await redis_service.initialize()
|
||||
if not initialized:
|
||||
|
||||
Reference in New Issue
Block a user