Skip to content

Commit 252557f

Browse files
committed
Retry next port on failure to start
Reset runner started on stop. Catch all exception for retries. New thread on retry.
1 parent 6b4f917 commit 252557f

File tree

1 file changed

+33
-14
lines changed

1 file changed

+33
-14
lines changed

dash/testing/application_runners.py

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,12 @@
1212
import runpy
1313
import requests
1414

15-
from dash.testing.errors import NoAppFoundError, TestingTimeoutError, ServerCloseError
15+
from dash.testing.errors import (
16+
NoAppFoundError,
17+
TestingTimeoutError,
18+
ServerCloseError,
19+
DashAppLoadingError,
20+
)
1621
from dash.testing import wait
1722

1823

@@ -146,37 +151,51 @@ def _handle_error():
146151

147152
app.server.errorhandler(500)(_handle_error)
148153

154+
if self.thread and self.thread.is_alive():
155+
self.stop()
156+
149157
def run():
150158
app.scripts.config.serve_locally = True
151159
app.css.config.serve_locally = True
160+
161+
options = kwargs.copy()
162+
152163
if "port" not in kwargs:
153-
kwargs["port"] = self.port = BaseDashRunner._next_port
164+
options["port"] = self.port = BaseDashRunner._next_port
154165
BaseDashRunner._next_port += 1
155166
else:
156-
self.port = kwargs["port"]
167+
self.port = options["port"]
157168

158169
try:
159-
app.run_server(threaded=True, **kwargs)
170+
app.run_server(threaded=True, **options)
160171
except SystemExit:
161172
logger.info("Server stopped")
162173

163-
self.thread = KillerThread(target=run)
164-
self.thread.daemon = True
165-
try:
166-
self.thread.start()
167-
except RuntimeError: # multiple call on same thread
168-
logger.exception("threaded server failed to start")
169-
self.started = False
174+
retries = 0
170175

171-
self.started = self.thread.is_alive()
176+
while not self.started and retries < 3:
177+
try:
178+
self.thread = KillerThread(target=run)
179+
self.thread.daemon = True
180+
self.thread.start()
181+
# wait until server is able to answer http request
182+
wait.until(lambda: self.accessible(self.url), timeout=2)
183+
self.started = self.thread.is_alive()
184+
except Exception as err: # pylint: disable=broad-except
185+
logger.exception(err)
186+
self.started = False
187+
retries += 1
188+
BaseDashRunner._next_port += 1
172189

173-
# wait until server is able to answer http request
174-
wait.until(lambda: self.accessible(self.url), timeout=1)
190+
self.started = self.thread.is_alive()
191+
if not self.started:
192+
raise DashAppLoadingError("threaded server failed to start")
175193

176194
def stop(self):
177195
self.thread.kill()
178196
self.thread.join()
179197
wait.until_not(self.thread.is_alive, self.stop_timeout)
198+
self.started = False
180199

181200

182201
class ProcessRunner(BaseDashRunner):

0 commit comments

Comments
 (0)