Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings
This repository was archived by the owner on Aug 29, 2025. It is now read-only.

Commit cd9afe1

Browse files
committed
Fix shutdown deprecation, #63
1 parent 8978912 commit cd9afe1

File tree

2 files changed

+35
-24
lines changed

2 files changed

+35
-24
lines changed

‎jupyter_dash/_stoppable_thread.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import ctypes
2+
import threading
3+
4+
5+
class StoppableThread(threading.Thread):
6+
def get_id(self):
7+
if hasattr(self, "_thread_id"):
8+
return self._thread_id
9+
for thread_id, thread in threading._active.items():
10+
if thread is self:
11+
return thread_id
12+
13+
def kill(self):
14+
thread_id = self.get_id()
15+
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(
16+
ctypes.c_long(thread_id), ctypes.py_object(SystemExit)
17+
)
18+
if res == 0:
19+
raise ValueError(f"Invalid thread id: {thread_id}")
20+
if res > 1:
21+
ctypes.pythonapi.PyThreadState_SetAsyncExc(ctypes.c_long(thread_id), None)
22+
raise SystemExit("Stopping thread failure")

‎jupyter_dash/jupyter_app.py

Lines changed: 13 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
import dash
22
import os
33
import requests
4-
from flask import request
54
import flask.cli
6-
from threading import Thread
75
from retrying import retry
86
import io
97
import re
@@ -19,6 +17,7 @@
1917
import uuid
2018

2119
from .comms import _dash_comm, _jupyter_config, _request_jupyter_config
20+
from ._stoppable_thread import StoppableThread
2221

2322

2423
def _get_skip(error: Exception):
@@ -49,6 +48,8 @@ class JupyterDash(dash.Dash):
4948
_in_colab = "google.colab" in sys.modules
5049
_token = str(uuid.uuid4())
5150

51+
_server_threads = {}
52+
5253
@classmethod
5354
def infer_jupyter_proxy_config(cls):
5455
"""
@@ -138,15 +139,6 @@ def __init__(self, name=None, server_url=None, **kwargs):
138139

139140
self.server_url = server_url
140141

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-
150142
# Register route that we can use to poll to see when server is running
151143
@self.server.route('/_alive_' + JupyterDash._token, methods=['GET'])
152144
def alive():
@@ -225,7 +217,9 @@ def run_server(
225217
inline_exceptions = mode == "inline"
226218

227219
# 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()
229223

230224
# Configure pathname prefix
231225
requests_pathname_prefix = self.config.get('requests_pathname_prefix', None)
@@ -297,12 +291,17 @@ def run_server(
297291
wait_exponential_max=1000
298292
)
299293
def run():
300-
super_run_server(**kwargs)
294+
try:
295+
super_run_server(**kwargs)
296+
except SystemExit:
297+
pass
301298

302-
thread = Thread(target=run)
299+
thread = StoppableThread(target=run)
303300
thread.setDaemon(True)
304301
thread.start()
305302

303+
self._server_threads[(host, port)] = thread
304+
306305
# Wait for server to start up
307306
alive_url = "http://{host}:{port}/_alive_{token}".format(
308307
host=host, port=port, token=JupyterDash._token
@@ -414,16 +413,6 @@ def _wrap_errors(error):
414413

415414
return html_str, 500
416415

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

428417
def _custom_formatargvalues(
429418
args, varargs, varkw, locals,

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /