Skip to content

Commit 24612ad

Browse files
authored
Fix dispatcher idle hang and add pytest timeouts (langgenius#26998)
1 parent 06649f6 commit 24612ad

13 files changed

Lines changed: 62 additions & 16 deletions

File tree

api/core/workflow/graph_engine/orchestration/dispatcher.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ def _dispatcher_loop(self) -> None:
9999
self._execution_coordinator.check_commands()
100100
self._event_queue.task_done()
101101
except queue.Empty:
102+
# Process commands even when no new events arrive so abort requests are not missed
103+
self._execution_coordinator.check_commands()
102104
# Check if execution is complete
103105
if self._execution_coordinator.is_execution_complete():
104106
break

api/pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ dev = [
166166
"mypy~=1.17.1",
167167
# "locust>=2.40.4", # Temporarily removed due to compatibility issues. Uncomment when resolved.
168168
"sseclient-py>=1.8.0",
169+
"pytest-timeout>=2.4.0",
169170
]
170171

171172
############################################################

api/tests/unit_tests/core/workflow/graph_engine/test_dispatcher.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,10 +95,10 @@ def _make_succeeded_event() -> NodeRunSucceededEvent:
9595
)
9696

9797

98-
def test_dispatcher_checks_commands_after_node_completion() -> None:
99-
"""Dispatcher should only check commands after node completion events."""
98+
def test_dispatcher_checks_commands_during_idle_and_on_completion() -> None:
99+
"""Dispatcher polls commands when idle and re-checks after completion events."""
100100
started_checks = _run_dispatcher_for_event(_make_started_event())
101101
succeeded_checks = _run_dispatcher_for_event(_make_succeeded_event())
102102

103-
assert started_checks == 0
104-
assert succeeded_checks == 1
103+
assert started_checks == 1
104+
assert succeeded_checks == 2

api/tests/unit_tests/services/test_metadata_bug_complete.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,10 @@ def test_2_business_logic_layer_crashes_on_none(self):
4141
mock_user.current_tenant_id = "tenant-123"
4242
mock_user.id = "user-456"
4343

44-
with patch("services.metadata_service.current_user", mock_user):
44+
with patch(
45+
"services.metadata_service.current_account_with_tenant",
46+
return_value=(mock_user, mock_user.current_tenant_id),
47+
):
4548
# Should crash with TypeError
4649
with pytest.raises(TypeError, match="object of type 'NoneType' has no len"):
4750
MetadataService.create_metadata("dataset-123", mock_metadata_args)
@@ -51,7 +54,10 @@ def test_2_business_logic_layer_crashes_on_none(self):
5154
mock_user.current_tenant_id = "tenant-123"
5255
mock_user.id = "user-456"
5356

54-
with patch("services.metadata_service.current_user", mock_user):
57+
with patch(
58+
"services.metadata_service.current_account_with_tenant",
59+
return_value=(mock_user, mock_user.current_tenant_id),
60+
):
5561
with pytest.raises(TypeError, match="object of type 'NoneType' has no len"):
5662
MetadataService.update_metadata_name("dataset-123", "metadata-456", None)
5763

api/tests/unit_tests/services/test_metadata_nullable_bug.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,10 @@ def test_metadata_service_create_with_none_name_crashes(self):
2929
mock_user.current_tenant_id = "tenant-123"
3030
mock_user.id = "user-456"
3131

32-
with patch("services.metadata_service.current_user", mock_user):
32+
with patch(
33+
"services.metadata_service.current_account_with_tenant",
34+
return_value=(mock_user, mock_user.current_tenant_id),
35+
):
3336
# This should crash with TypeError when calling len(None)
3437
with pytest.raises(TypeError, match="object of type 'NoneType' has no len"):
3538
MetadataService.create_metadata("dataset-123", mock_metadata_args)
@@ -40,7 +43,10 @@ def test_metadata_service_update_with_none_name_crashes(self):
4043
mock_user.current_tenant_id = "tenant-123"
4144
mock_user.id = "user-456"
4245

43-
with patch("services.metadata_service.current_user", mock_user):
46+
with patch(
47+
"services.metadata_service.current_account_with_tenant",
48+
return_value=(mock_user, mock_user.current_tenant_id),
49+
):
4450
# This should crash with TypeError when calling len(None)
4551
with pytest.raises(TypeError, match="object of type 'NoneType' has no len"):
4652
MetadataService.update_metadata_name("dataset-123", "metadata-456", None)
@@ -88,7 +94,10 @@ def test_integration_bug_scenario(self, app):
8894
mock_user.current_tenant_id = "tenant-123"
8995
mock_user.id = "user-456"
9096

91-
with patch("services.metadata_service.current_user", mock_user):
97+
with patch(
98+
"services.metadata_service.current_account_with_tenant",
99+
return_value=(mock_user, mock_user.current_tenant_id),
100+
):
92101
# Step 4: Service layer crashes on len(None)
93102
with pytest.raises(TypeError, match="object of type 'NoneType' has no len"):
94103
MetadataService.create_metadata("dataset-123", mock_metadata_args)

api/uv.lock

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dev/pytest/pytest_artifacts.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,6 @@ set -x
44
SCRIPT_DIR="$(dirname "$(realpath "$0")")"
55
cd "$SCRIPT_DIR/../.."
66

7-
pytest api/tests/artifact_tests/
7+
PYTEST_TIMEOUT="${PYTEST_TIMEOUT:-120}"
8+
9+
pytest --timeout "${PYTEST_TIMEOUT}" api/tests/artifact_tests/

dev/pytest/pytest_model_runtime.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ set -x
44
SCRIPT_DIR="$(dirname "$(realpath "$0")")"
55
cd "$SCRIPT_DIR/../.."
66

7-
pytest api/tests/integration_tests/model_runtime/anthropic \
7+
PYTEST_TIMEOUT="${PYTEST_TIMEOUT:-180}"
8+
9+
pytest --timeout "${PYTEST_TIMEOUT}" api/tests/integration_tests/model_runtime/anthropic \
810
api/tests/integration_tests/model_runtime/azure_openai \
911
api/tests/integration_tests/model_runtime/openai api/tests/integration_tests/model_runtime/chatglm \
1012
api/tests/integration_tests/model_runtime/google api/tests/integration_tests/model_runtime/xinference \

dev/pytest/pytest_testcontainers.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,6 @@ set -x
44
SCRIPT_DIR="$(dirname "$(realpath "$0")")"
55
cd "$SCRIPT_DIR/../.."
66

7-
pytest api/tests/test_containers_integration_tests
7+
PYTEST_TIMEOUT="${PYTEST_TIMEOUT:-120}"
8+
9+
pytest --timeout "${PYTEST_TIMEOUT}" api/tests/test_containers_integration_tests

dev/pytest/pytest_tools.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,6 @@ set -x
44
SCRIPT_DIR="$(dirname "$(realpath "$0")")"
55
cd "$SCRIPT_DIR/../.."
66

7-
pytest api/tests/integration_tests/tools
7+
PYTEST_TIMEOUT="${PYTEST_TIMEOUT:-120}"
8+
9+
pytest --timeout "${PYTEST_TIMEOUT}" api/tests/integration_tests/tools

0 commit comments

Comments
 (0)