ALL-4636 Resolution for connection leaks (#12144)

Co-authored-by: openhands <openhands@all-hands.dev>
This commit is contained in:
Tim O'Farrell 2025-12-23 12:02:56 -07:00 committed by GitHub
parent f6e7628bff
commit 8d0e7a92b8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 33 additions and 6 deletions

View File

@ -154,8 +154,10 @@ class SaasUserAuth(UserAuth):
try:
# TODO: I think we can do this in a single request if we refactor
with session_maker() as session:
tokens = session.query(AuthTokens).where(
AuthTokens.keycloak_user_id == self.user_id
tokens = (
session.query(AuthTokens)
.where(AuthTokens.keycloak_user_id == self.user_id)
.all()
)
for token in tokens:

View File

@ -510,6 +510,10 @@ async def delete_conversation(
if v1_result is not None:
return v1_result
# Close connections
await db_session.close()
await httpx_client.aclose()
# V0 conversation logic
return await _delete_v0_conversation(conversation_id, user_id)
@ -551,11 +555,8 @@ async def _try_delete_v1_conversation(
httpx_client,
)
)
except (ValueError, TypeError):
# Not a valid UUID, continue with V0 logic
pass
except Exception:
# Some other error, continue with V0 logic
# Continue with V0 logic
pass
return result

View File

@ -946,6 +946,10 @@ async def test_delete_conversation():
# Create a mock sandbox service
mock_sandbox_service = MagicMock()
# Create mock db_session and httpx_client
mock_db_session = AsyncMock()
mock_httpx_client = AsyncMock()
# Mock the conversation manager
with patch(
'openhands.server.routes.manage_conversations.conversation_manager'
@ -969,6 +973,8 @@ async def test_delete_conversation():
app_conversation_service=mock_app_conversation_service,
app_conversation_info_service=mock_app_conversation_info_service,
sandbox_service=mock_sandbox_service,
db_session=mock_db_session,
httpx_client=mock_httpx_client,
)
# Verify the result
@ -1090,6 +1096,10 @@ async def test_delete_v1_conversation_not_found():
)
mock_service.delete_app_conversation = AsyncMock(return_value=False)
# Create mock db_session and httpx_client
mock_db_session = AsyncMock()
mock_httpx_client = AsyncMock()
# Call delete_conversation with V1 conversation ID
result = await delete_conversation(
request=MagicMock(),
@ -1098,6 +1108,8 @@ async def test_delete_v1_conversation_not_found():
app_conversation_service=mock_service,
app_conversation_info_service=mock_info_service,
sandbox_service=mock_sandbox_service,
db_session=mock_db_session,
httpx_client=mock_httpx_client,
)
# Verify the result
@ -1171,6 +1183,10 @@ async def test_delete_v1_conversation_invalid_uuid():
mock_sandbox_service = MagicMock()
mock_sandbox_service_dep.return_value = mock_sandbox_service
# Create mock db_session and httpx_client
mock_db_session = AsyncMock()
mock_httpx_client = AsyncMock()
# Call delete_conversation
result = await delete_conversation(
request=MagicMock(),
@ -1179,6 +1195,8 @@ async def test_delete_v1_conversation_invalid_uuid():
app_conversation_service=mock_service,
app_conversation_info_service=mock_info_service,
sandbox_service=mock_sandbox_service,
db_session=mock_db_session,
httpx_client=mock_httpx_client,
)
# Verify the result
@ -1264,6 +1282,10 @@ async def test_delete_v1_conversation_service_error():
mock_runtime_cls.delete = AsyncMock()
mock_get_runtime_cls.return_value = mock_runtime_cls
# Create mock db_session and httpx_client
mock_db_session = AsyncMock()
mock_httpx_client = AsyncMock()
# Call delete_conversation
result = await delete_conversation(
request=MagicMock(),
@ -1272,6 +1294,8 @@ async def test_delete_v1_conversation_service_error():
app_conversation_service=mock_service,
app_conversation_info_service=mock_info_service,
sandbox_service=mock_sandbox_service,
db_session=mock_db_session,
httpx_client=mock_httpx_client,
)
# Verify the result (should fallback to V0)