Skip to content

Commit efc5697

Browse files
authored
port communication over a multiprocessing queue in fixtures (Open-MSS#2969)
1 parent 951a513 commit efc5697

File tree

1 file changed

+40
-10
lines changed

1 file changed

+40
-10
lines changed

tests/fixtures.py

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ def mscolab_session_server(mscolab_session_app, mscolab_session_managers):
124124
with _running_eventlet_server(mscolab_session_app) as url:
125125
# Wait until the Flask-SocketIO server is ready for connections
126126
sio = socketio.Client()
127-
sio.connect(url, retry=True)
127+
sio.connect(url, retry=True, wait_timeout=60)
128128
sio.disconnect()
129129
del sio
130130
yield url
@@ -186,32 +186,62 @@ def mswms_server(mswms_app):
186186
yield url
187187

188188

189+
def _start_eventlet_server(host, port_queue, app):
190+
"""
191+
Starts the Eventlet server and sends the chosen port back to the parent process.
192+
"""
193+
sock = eventlet.listen((host, 0))
194+
port = sock.getsockname()[1]
195+
port_queue.put(port)
196+
eventlet.wsgi.server(sock, app, log_output=False)
197+
198+
189199
@contextmanager
190200
def _running_eventlet_server(app):
191201
"""Context manager that starts the app in an eventlet server and returns its URL."""
192202
scheme = "http"
193203
host = "127.0.0.1"
194-
socket = eventlet.listen((host, 0))
195-
port = socket.getsockname()[1]
196-
url = f"{scheme}://{host}:{port}"
197-
app.config['URL'] = url
204+
198205
if "fork" not in multiprocessing.get_all_start_methods():
199206
pytest.skip("requires the multiprocessing start_method 'fork', which is unavailable on this system")
207+
200208
ctx = multiprocessing.get_context("fork")
201-
process = ctx.Process(target=eventlet.wsgi.server, args=(socket, app), daemon=True)
209+
# We are using a queue to retrieve the port selected in the child process.
210+
port_queue = ctx.Queue()
211+
212+
process = ctx.Process(target=_start_eventlet_server, args=(host, port_queue, app), daemon=True)
202213
try:
203214
process.start()
215+
# Retrieve the port from the queue
216+
try:
217+
port = port_queue.get(timeout=10)
218+
except multiprocessing.queues.Empty:
219+
raise RuntimeError("Could not retrieve port from server process")
220+
221+
url = f"{scheme}://{host}:{port}"
222+
app.config['URL'] = url
223+
204224
start_time = time.time()
205225
sleep_time = 0.01
206-
while not is_url_response_ok(urllib.parse.urljoin(url, "index")):
207-
if (time.time() - start_time) > 5:
208-
raise RuntimeError(f"Server did not start within 5 seconds at {url}")
226+
time_out = 20
227+
# we check only for the root url, index.html may take longer
228+
readiness_url = urllib.parse.urljoin(url, "/")
229+
while not is_url_response_ok(readiness_url):
230+
if not process.is_alive():
231+
# show the exitcode for further debugging
232+
raise RuntimeError(f"Server process exited early with code {process.exitcode} at {url}")
233+
if (time.time() - start_time) > time_out:
234+
raise RuntimeError(f"Server did not start within {time_out} seconds at {url}")
209235
time.sleep(sleep_time)
210236
sleep_time *= 2
211237
if sleep_time > 1:
212238
sleep_time = 1
213239
yield url
214240
finally:
215241
process.terminate()
216-
process.join(10)
242+
process.join(timeout=10)
243+
if process.is_alive():
244+
# when it is still alive after 10 seconds, kill it
245+
process.kill()
246+
process.join(timeout=5)
217247
process.close()

0 commit comments

Comments
 (0)