@@ -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