Skip to content

Commit 13c6a59

Browse files
Properly separate unit tests from system tests WRT subprocess (#735)
Fixes #601
1 parent 2d77d61 commit 13c6a59

File tree

5 files changed

+198
-249
lines changed

5 files changed

+198
-249
lines changed

src/blueapi/service/main.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,12 @@ def _runner() -> WorkerDispatcher:
5959
return RUNNER
6060

6161

62-
def setup_runner(config: ApplicationConfig | None = None, use_subprocess: bool = True):
62+
def setup_runner(
63+
config: ApplicationConfig | None = None,
64+
runner: WorkerDispatcher | None = None,
65+
):
6366
global RUNNER
64-
runner = WorkerDispatcher(config, use_subprocess)
67+
runner = runner or WorkerDispatcher(config)
6568
runner.start()
6669

6770
RUNNER = runner

src/blueapi/service/runner.py

Lines changed: 12 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
from typing import Any, ParamSpec, TypeVar
99

1010
from observability_utils.tracing import (
11-
add_span_attributes,
1211
get_context_propagator,
1312
get_tracer,
1413
start_as_current_span,
@@ -44,17 +43,19 @@ class WorkerDispatcher:
4443

4544
_config: ApplicationConfig
4645
_subprocess: PoolClass | None
47-
_use_subprocess: bool
4846
_state: EnvironmentResponse
4947

5048
def __init__(
5149
self,
5250
config: ApplicationConfig | None = None,
53-
use_subprocess: bool = True,
51+
subprocess_factory: Callable[[], PoolClass] | None = None,
5452
) -> None:
53+
def default_subprocess_factory():
54+
return Pool(initializer=_init_worker, processes=1)
55+
5556
self._config = config or ApplicationConfig()
5657
self._subprocess = None
57-
self._use_subprocess = use_subprocess
58+
self._subprocess_factory = subprocess_factory or default_subprocess_factory
5859
self._state = EnvironmentResponse(
5960
initialized=False,
6061
)
@@ -68,12 +69,8 @@ def reload(self):
6869

6970
@start_as_current_span(TRACER)
7071
def start(self):
71-
add_span_attributes(
72-
{"_use_subprocess": self._use_subprocess, "_config": str(self._config)}
73-
)
7472
try:
75-
if self._use_subprocess:
76-
self._subprocess = Pool(initializer=_init_worker, processes=1)
73+
self._subprocess = self._subprocess_factory()
7774
self.run(setup, self._config)
7875
self._state = EnvironmentResponse(initialized=True)
7976
except Exception as e:
@@ -107,40 +104,25 @@ def run(
107104
function: Callable[P, T],
108105
*args: P.args,
109106
**kwargs: P.kwargs,
110-
) -> T:
111-
"""Calls the supplied function, which is modified to accept a dict as it's new
112-
first param, before being passed to the subprocess runner, or just run in place.
113-
"""
114-
add_span_attributes({"use_subprocess": self._use_subprocess})
115-
if self._use_subprocess:
116-
return self._run_in_subprocess(function, *args, **kwargs)
117-
else:
118-
return function(*args, **kwargs)
119-
120-
@start_as_current_span(TRACER, "function", "args", "kwargs")
121-
def _run_in_subprocess(
122-
self,
123-
function: Callable[P, T],
124-
*args: P.args,
125-
**kwargs: P.kwargs,
126107
) -> T:
127108
"""Call the supplied function, passing the current Span ID, if one
128-
exists,from the observability context inro the _rpc caller function.
109+
exists,from the observability context into the import_and_run_function
110+
caller function.
111+
129112
When this is deserialized in and run by the subprocess, this will allow
130113
its functions to use the corresponding span as their parent span."""
114+
131115
if self._subprocess is None:
132116
raise InvalidRunnerStateError("Subprocess runner has not been started")
133117
if not (hasattr(function, "__name__") and hasattr(function, "__module__")):
134118
raise RpcError(f"{function} is anonymous, cannot be run in subprocess")
135-
if not callable(function):
136-
raise RpcError(f"{function} is not Callable, cannot be run in subprocess")
137119
try:
138120
return_type = inspect.signature(function).return_annotation
139121
except TypeError:
140122
return_type = None
141123

142124
return self._subprocess.apply(
143-
_rpc,
125+
import_and_run_function,
144126
(
145127
function.__module__,
146128
function.__name__,
@@ -164,7 +146,7 @@ def __init__(self, message):
164146
class RpcError(Exception): ...
165147

166148

167-
def _rpc(
149+
def import_and_run_function(
168150
module_name: str,
169151
function_name: str,
170152
expected_type: type[T] | None,

0 commit comments

Comments
 (0)