From f5b1904d093b64c6887f2d3bc4602d30f95dcf3f Mon Sep 17 00:00:00 2001 From: Anas Khan <83116240+anxkhn@users.noreply.github.com> Date: Mon, 27 Jul 2026 20:10:00 +0530 Subject: [PATCH] fix(integrations): close AsyncDaytona client in DaytonaEnvironment.close() Await the AsyncDaytona client close method after deleting its sandbox so repeated environment lifecycles do not leak HTTP sessions. Verify that close is awaited exactly once. Signed-off-by: Anas Khan <83116240+anxkhn@users.noreply.github.com> --- src/google/adk/integrations/daytona/_daytona_environment.py | 4 ++++ .../integrations/daytona/test_daytona_environment.py | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/src/google/adk/integrations/daytona/_daytona_environment.py b/src/google/adk/integrations/daytona/_daytona_environment.py index 6c8990c86f3..d5f6c789a8f 100644 --- a/src/google/adk/integrations/daytona/_daytona_environment.py +++ b/src/google/adk/integrations/daytona/_daytona_environment.py @@ -96,6 +96,10 @@ async def close(self) -> None: if self._sandbox is not None: await self._sandbox.delete() self._sandbox = None + if self._client is not None: + # Close the AsyncDaytona client to release its underlying HTTP + # sessions and avoid leaking sockets across create/close cycles. + await self._client.close() # type: ignore[no-untyped-call] self._client = None self._is_initialized = False diff --git a/tests/unittests/integrations/daytona/test_daytona_environment.py b/tests/unittests/integrations/daytona/test_daytona_environment.py index c4ee0b1b806..8436959f689 100644 --- a/tests/unittests/integrations/daytona/test_daytona_environment.py +++ b/tests/unittests/integrations/daytona/test_daytona_environment.py @@ -47,6 +47,7 @@ def _daytona_patch(sandbox: mock.MagicMock): """Patch AsyncDaytona to return a mock client.""" mock_client = mock.MagicMock(name="AsyncDaytona") mock_client.create = mock.AsyncMock(return_value=sandbox) + mock_client.close = mock.AsyncMock() with mock.patch.object(daytona, "AsyncDaytona", autospec=True) as mock_class: mock_class.return_value = mock_client @@ -103,14 +104,18 @@ async def test_close_deletes_sandbox_and_is_idempotent(daytona_patch, sandbox): env = DaytonaEnvironment() await env.initialize() assert env.is_initialized is True + client = daytona_patch.return_value await env.close() sandbox.delete.assert_awaited_once() + client.close.assert_awaited_once() assert env._sandbox is None + assert env._client is None assert env.is_initialized is False # Second close is a no-op. await env.close() sandbox.delete.assert_awaited_once() + client.close.assert_awaited_once() async def test_working_dir_requires_initialize():