Skip to content

Commit e9f1717

Browse files
authored
Fix flaky backend timeout handling (#2204)
1 parent 4065e3a commit e9f1717

2 files changed

Lines changed: 44 additions & 25 deletions

File tree

‎.github/workflows/backend.yml‎

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -251,16 +251,17 @@ jobs:
251251
#
252252
# pytest-cov + pytest-xdist handle per-worker coverage merging.
253253
#
254-
# ``--timeout=600 --timeout-method=thread``: a per-test hang guard.
254+
# ``--timeout=600 --timeout-method=signal``: a per-test hang guard.
255255
# Without it a single test that blocks on a starved service (the
256256
# 2-core runner runs ``-n auto`` workers alongside the docling/embedder
257257
# ML containers) hangs its worker until the 100-min step ceiling, with
258258
# no traceback. 600s is ~10x the slowest legitimate test (~57s) so it
259-
# never false-positives, while turning an 83-min silent hang into a
260-
# fast failure that dumps the offending test's stack. The ``thread``
261-
# method is required: it interrupts blocking C calls (sockets) that the
262-
# default ``signal`` method cannot, and works inside xdist workers.
263-
docker compose -f test.yml run django pytest --cov --cov-report=xml -n auto --dist loadscope --timeout=600 --timeout-method=thread
259+
# never false-positives, while turning a silent hang into a failure
260+
# that identifies the offending test. On Linux xdist workers the
261+
# signal method raises a pytest failure in the worker's main thread.
262+
# The thread method hard-exits the worker, which can leave the xdist
263+
# controller waiting until the outer 100-minute timeout.
264+
docker compose -f test.yml run django pytest --cov --cov-report=xml -n auto --dist loadscope --timeout=600 --timeout-method=signal
264265
265266
- name: Verify Coverage File Exists
266267
run: |

‎opencontractserver/tests/test_conversation_search.py‎

Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@
88
- GraphQL query integration
99
"""
1010

11+
from unittest.mock import patch
12+
1113
import pytest
1214
from django.contrib.auth import get_user_model
1315
from django.core.files.base import ContentFile
14-
from django.test import TestCase, override_settings
16+
from django.test import SimpleTestCase, TestCase, override_settings
1517
from graphql_relay import to_global_id
1618

1719
from config.graphql.schema import schema
@@ -527,24 +529,6 @@ def test_message_search_with_query_text(self):
527529
"len(" in error_msg or "embedder" in error_msg or "vector" in error_msg
528530
)
529531

530-
def test_message_search_nonexistent_user(self):
531-
"""Test message search with nonexistent user."""
532-
store = CoreChatMessageVectorStore(
533-
user_id=99999, # Non-existent user
534-
corpus_id=self.corpus.id,
535-
embedder_path="test/embedder",
536-
)
537-
538-
query = VectorSearchQuery(
539-
query_embedding=[0.1] * 384,
540-
similarity_top_k=10,
541-
)
542-
543-
results = store.search(query)
544-
545-
# Should return empty results, not crash
546-
self.assertEqual(len(results), 0)
547-
548532
def test_message_search_missing_query_raises_error(self):
549533
"""Test that message search raises ValueError when neither text nor embedding provided."""
550534
store = CoreChatMessageVectorStore(
@@ -563,6 +547,40 @@ def test_message_search_missing_query_raises_error(self):
563547
self.assertIn("Either query_text or query_embedding", str(ctx.exception))
564548

565549

550+
class MessageVectorSearchMissingUserTest(SimpleTestCase):
551+
"""Test the missing-user branch without database or embedder dependencies."""
552+
553+
def test_message_search_nonexistent_user(self):
554+
"""A missing user returns no results without attempting vector search."""
555+
missing_user_id = 99999
556+
557+
with (
558+
patch(
559+
"opencontractserver.llms.vector_stores."
560+
"core_conversation_vector_stores.get_embedder",
561+
return_value=(None, "test/embedder"),
562+
),
563+
patch("django.contrib.auth.get_user_model") as mock_get_user_model,
564+
):
565+
mock_user_model = mock_get_user_model.return_value
566+
mock_user_model.DoesNotExist = User.DoesNotExist
567+
mock_user_model.objects.get.side_effect = User.DoesNotExist
568+
569+
store = CoreChatMessageVectorStore(
570+
user_id=missing_user_id,
571+
embedder_path="test/embedder",
572+
)
573+
query = VectorSearchQuery(
574+
query_embedding=[0.1] * 384,
575+
similarity_top_k=10,
576+
)
577+
578+
results = store.search(query)
579+
580+
self.assertEqual(results, [])
581+
mock_user_model.objects.get.assert_called_once_with(id=missing_user_id)
582+
583+
566584
class GraphQLConversationSearchTest(TestCase):
567585
"""Test GraphQL search queries."""
568586

0 commit comments

Comments
 (0)