|
1 | 1 | import dash |
2 | 2 | import os |
3 | 3 | import requests |
4 | | -from flask import request |
5 | 4 | import flask.cli |
6 | | -from threading import Thread |
7 | 5 | from retrying import retry |
8 | 6 | import io |
9 | 7 | import re |
|
19 | 17 | import uuid |
20 | 18 |
|
21 | 19 | from .comms import _dash_comm, _jupyter_config, _request_jupyter_config |
| 20 | +from ._stoppable_thread import StoppableThread |
22 | 21 |
|
23 | 22 |
|
24 | 23 | def _get_skip(error: Exception): |
@@ -49,6 +48,8 @@ class JupyterDash(dash.Dash): |
49 | 48 | _in_colab = "google.colab" in sys.modules |
50 | 49 | _token = str(uuid.uuid4()) |
51 | 50 |
|
| 51 | + _server_threads = {} |
| 52 | + |
52 | 53 | @classmethod |
53 | 54 | def infer_jupyter_proxy_config(cls): |
54 | 55 | """ |
@@ -138,15 +139,6 @@ def __init__(self, name=None, server_url=None, **kwargs): |
138 | 139 |
|
139 | 140 | self.server_url = server_url |
140 | 141 |
|
141 | | - # Register route to shut down server |
142 | | - @self.server.route('/_shutdown_' + JupyterDash._token, methods=['GET']) |
143 | | - def shutdown(): |
144 | | - func = request.environ.get('werkzeug.server.shutdown') |
145 | | - if func is None: |
146 | | - raise RuntimeError('Not running with the Werkzeug Server') |
147 | | - func() |
148 | | - return 'Server shutting down...' |
149 | | - |
150 | 142 | # Register route that we can use to poll to see when server is running |
151 | 143 | @self.server.route('/_alive_' + JupyterDash._token, methods=['GET']) |
152 | 144 | def alive(): |
@@ -225,7 +217,9 @@ def run_server( |
225 | 217 | inline_exceptions = mode == "inline" |
226 | 218 |
|
227 | 219 | # Terminate any existing server using this port |
228 | | - self._terminate_server_for_port(host, port) |
| 220 | + old_server = self._server_threads.get((host, port)) |
| 221 | + if old_server: |
| 222 | + old_server.kill() |
229 | 223 |
|
230 | 224 | # Configure pathname prefix |
231 | 225 | requests_pathname_prefix = self.config.get('requests_pathname_prefix', None) |
@@ -297,12 +291,17 @@ def run_server( |
297 | 291 | wait_exponential_max=1000 |
298 | 292 | ) |
299 | 293 | def run(): |
300 | | - super_run_server(**kwargs) |
| 294 | + try: |
| 295 | + super_run_server(**kwargs) |
| 296 | + except SystemExit: |
| 297 | + pass |
301 | 298 |
|
302 | | - thread = Thread(target=run) |
| 299 | + thread = StoppableThread(target=run) |
303 | 300 | thread.setDaemon(True) |
304 | 301 | thread.start() |
305 | 302 |
|
| 303 | + self._server_threads[(host, port)] = thread |
| 304 | + |
306 | 305 | # Wait for server to start up |
307 | 306 | alive_url = "http://{host}:{port}/_alive_{token}".format( |
308 | 307 | host=host, port=port, token=JupyterDash._token |
@@ -414,16 +413,6 @@ def _wrap_errors(error): |
414 | 413 |
|
415 | 414 | return html_str, 500 |
416 | 415 |
|
417 | | - @classmethod |
418 | | - def _terminate_server_for_port(cls, host, port): |
419 | | - shutdown_url = "http://{host}:{port}/_shutdown_{token}".format( |
420 | | - host=host, port=port, token=JupyterDash._token |
421 | | - ) |
422 | | - try: |
423 | | - response = requests.get(shutdown_url) |
424 | | - except Exception as e: |
425 | | - pass |
426 | | - |
427 | 416 |
|
428 | 417 | def _custom_formatargvalues( |
429 | 418 | args, varargs, varkw, locals, |
|
0 commit comments