Skip to content

Commit e18b9be

Browse files
authored
Acqp-323 prevent blank connection errors in STOMP connections (#803)
Add handler functions to check for Exceptions with message that are None, Empty String or a String that consists only of spaces Fixes #792
1 parent 07bd6ba commit e18b9be

File tree

2 files changed

+43
-16
lines changed

2 files changed

+43
-16
lines changed

src/blueapi/service/runner.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
P = ParamSpec("P")
3131
T = TypeVar("T")
3232

33+
BLANK_REPORT = "The source message was blank"
34+
3335

3436
def _init_worker():
3537
# Replace sigint to allow subprocess to be terminated
@@ -80,12 +82,12 @@ def start(self):
8082
initialized=True,
8183
)
8284
except Exception as e:
85+
LOGGER.exception(e)
8386
self._state = EnvironmentResponse(
8487
environment_id=environment_id,
8588
initialized=False,
86-
error_message=str(e),
89+
error_message=_safe_exception_message(e),
8790
)
88-
LOGGER.exception(e)
8991

9092
@start_as_current_span(TRACER)
9193
def stop(self):
@@ -101,12 +103,12 @@ def stop(self):
101103
error_message=self._state.error_message,
102104
)
103105
except Exception as e:
106+
LOGGER.exception(e)
104107
self._state = EnvironmentResponse(
105108
environment_id=environment_id,
106109
initialized=False,
107-
error_message=str(e),
110+
error_message=_safe_exception_message(e),
108111
)
109-
LOGGER.exception(e)
110112

111113
@start_as_current_span(TRACER, "function", "args", "kwargs")
112114
def run(
@@ -188,3 +190,11 @@ def _validate_function(func: Any, function_name: str) -> Callable:
188190
elif not callable(func):
189191
raise RpcError(f"{function_name}: Object in subprocess is not a function")
190192
return func
193+
194+
195+
def _safe_exception_message(e: Exception) -> str:
196+
return _safe_message(type(e).__name__, str(e))
197+
198+
199+
def _safe_message(owner: str, message: str | None) -> str:
200+
return f"{owner}: {BLANK_REPORT if (not message or message.isspace()) else message}"

tests/unit_tests/service/test_runner.py

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
InvalidRunnerStateError,
1818
RpcError,
1919
WorkerDispatcher,
20+
_safe_exception_message,
2021
import_and_run_function,
2122
)
2223

@@ -71,19 +72,33 @@ def test_raises_if_used_before_started(runner: WorkerDispatcher):
7172
runner.run(interface.get_plans)
7273

7374

74-
def test_error_on_runner_setup(runner: WorkerDispatcher, mock_subprocess: Mock):
75-
error_message = "Intentional start_worker exception"
76-
environment_id = uuid.uuid4()
77-
expected_state = EnvironmentResponse(
78-
environment_id=environment_id,
79-
initialized=False,
80-
error_message=error_message,
75+
@pytest.mark.parametrize(
76+
"message",
77+
[
78+
None,
79+
"",
80+
" ",
81+
"Intentional start_worker exception",
82+
],
83+
)
84+
def test_using_safe_exception_message_copes_with_all_message_types_on_runner_setup(
85+
runner: WorkerDispatcher, mock_subprocess: Mock, message: str | None
86+
):
87+
try:
88+
raise Exception() if message is None else Exception(message)
89+
except Exception as e:
90+
expected_state = EnvironmentResponse(
91+
environment_id=uuid.uuid4(),
92+
initialized=False,
93+
error_message=_safe_exception_message(e),
94+
)
95+
mock_subprocess.apply.side_effect = (
96+
Exception() if message is None else Exception(message)
8197
)
82-
mock_subprocess.apply.side_effect = Exception(error_message)
8398

84-
# Calling reload here instead of start also indirectly
85-
# tests that stop() doesn't raise if there is no error message
86-
# and the runner is not yet initialised
99+
# Calling reload here instead of start also indirectly tests
100+
# that stop() doesn't raise if there is no error message and the
101+
# runner is not yet initialised.
87102
runner.reload()
88103
state = runner.state
89104
expected_state.environment_id = state.environment_id
@@ -116,7 +131,9 @@ def test_can_reload_after_an_error(pool_mock: MagicMock):
116131
runner.start()
117132
current_env = runner.state.environment_id
118133
assert runner.state == EnvironmentResponse(
119-
environment_id=current_env, initialized=False, error_message="invalid code"
134+
environment_id=current_env,
135+
initialized=False,
136+
error_message="SyntaxError: invalid code",
120137
)
121138

122139
runner.reload()

0 commit comments

Comments
 (0)