Skip to content

Commit d67169f

Browse files
committed
use a child for the listening socket
1 parent 18a9d8a commit d67169f

File tree

1 file changed

+38
-5
lines changed

1 file changed

+38
-5
lines changed

tests/fixtures.py

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -196,16 +196,44 @@ def _running_eventlet_server(app):
196196
"""Context manager that starts the app in an eventlet server and returns its URL."""
197197
scheme = "http"
198198
host = "127.0.0.1"
199-
socket = eventlet.listen((host, 0))
200-
port = socket.getsockname()[1]
201-
url = f"{scheme}://{host}:{port}"
202-
app.config['URL'] = url
199+
203200
if "fork" not in multiprocessing.get_all_start_methods():
204201
pytest.skip("requires the multiprocessing start_method 'fork', which is unavailable on this system")
202+
205203
ctx = multiprocessing.get_context("fork")
206-
process = ctx.Process(target=eventlet.wsgi.server, args=(socket, app), daemon=True)
204+
205+
def _serve_in_child(conn, _app, _host, _scheme):
206+
# Create the listening socket inside the child to avoid passing GreenSocket/FD across fork.
207+
sock = eventlet.listen((_host, 0))
208+
port = sock.getsockname()[1]
209+
url = f"{_scheme}://{_host}:{port}"
210+
211+
try:
212+
_app.config["URL"] = url
213+
except Exception:
214+
# If app/config is not writable for some reason, still start server.
215+
pass
216+
217+
conn.send(port)
218+
conn.close()
219+
220+
# Run until terminated by parent.
221+
eventlet.wsgi.server(sock, _app)
222+
223+
parent_conn, child_conn = ctx.Pipe(duplex=False)
224+
process = ctx.Process(target=_serve_in_child, args=(child_conn, app, host, scheme), daemon=True)
225+
207226
try:
208227
process.start()
228+
229+
# Wait for the child to report the bound port.
230+
if not parent_conn.poll(5):
231+
raise RuntimeError("Server did not report its port within 5 seconds")
232+
port = parent_conn.recv()
233+
234+
url = f"{scheme}://{host}:{port}"
235+
app.config["URL"] = url
236+
209237
start_time = time.time()
210238
sleep_time = 0.01
211239
while not is_url_response_ok(urllib.parse.urljoin(url, "index")):
@@ -215,8 +243,13 @@ def _running_eventlet_server(app):
215243
sleep_time *= 2
216244
if sleep_time > 1:
217245
sleep_time = 1
246+
218247
yield url
219248
finally:
249+
try:
250+
parent_conn.close()
251+
except Exception:
252+
pass
220253
process.terminate()
221254
process.join(10)
222255
process.close()

0 commit comments

Comments
 (0)