|
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