Skip to content

Commit d17e464

Browse files
committed
Warn when explicit dashboard requests fall back
1 parent 6f721b8 commit d17e464

3 files changed

Lines changed: 94 additions & 50 deletions

File tree

distributed/deploy/local.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,6 @@ def __init__(
233233
port=scheduler_port,
234234
interface=interface,
235235
protocol=protocol,
236-
dashboard=dashboard_address is not None,
237236
dashboard_address=dashboard_address,
238237
blocked_handlers=blocked_handlers,
239238
),

distributed/http/scheduler/tests/test_missing_bokeh.py

Lines changed: 85 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -8,67 +8,104 @@
88
from tornado.httpclient import AsyncHTTPClient
99

1010
from distributed import Scheduler
11-
from distributed.utils_test import gen_test
11+
from distributed.utils_test import captured_logger, gen_test
1212

1313

1414
@gen_test()
1515
async def test_missing_bokeh():
16-
with mock.patch.dict(sys.modules, {"bokeh": None}):
17-
# NOTE: mocking here is fiddly; if any of these get refactored or import order
18-
# changes, this may break.
19-
sys.modules.pop("distributed.dashboard.scheduler", None)
20-
sys.modules.pop("distributed.dashboard.core", None)
21-
sys.modules.pop("distributed.dashboard.utils", None)
22-
23-
async with Scheduler(dashboard_address=":0") as s:
24-
http_client = AsyncHTTPClient()
25-
response = await http_client.fetch(
26-
f"http://localhost:{s.http_server.port}/status"
27-
)
28-
assert response.code == 200
29-
body = response.body.decode()
30-
assert "Dask needs bokeh" in body
16+
with captured_logger("distributed.scheduler") as log:
17+
with mock.patch.dict(sys.modules, {"bokeh": None}):
18+
# NOTE: mocking here is fiddly; if any of these get refactored or import order
19+
# changes, this may break.
20+
sys.modules.pop("distributed.dashboard.scheduler", None)
21+
sys.modules.pop("distributed.dashboard.core", None)
22+
sys.modules.pop("distributed.dashboard.utils", None)
23+
24+
async with Scheduler(dashboard=True, dashboard_address=":0") as s:
25+
http_client = AsyncHTTPClient()
26+
response = await http_client.fetch(
27+
f"http://localhost:{s.http_server.port}/status"
28+
)
29+
assert response.code == 200
30+
body = response.body.decode()
31+
assert "Dask needs bokeh" in body
32+
33+
assert "Dashboard is disabled" in log.getvalue()
34+
35+
36+
@gen_test()
37+
async def test_implicit_dashboard_request_stays_silent():
38+
with captured_logger("distributed.scheduler") as log:
39+
with mock.patch.dict(sys.modules, {"bokeh": None}):
40+
sys.modules.pop("distributed.dashboard.scheduler", None)
41+
sys.modules.pop("distributed.dashboard.core", None)
42+
sys.modules.pop("distributed.dashboard.utils", None)
43+
44+
async with Scheduler(dashboard_address=":0") as s:
45+
http_client = AsyncHTTPClient()
46+
response = await http_client.fetch(
47+
f"http://localhost:{s.http_server.port}/status"
48+
)
49+
assert response.code == 200
50+
body = response.body.decode()
51+
assert "Dask needs bokeh" in body
52+
53+
assert "Dashboard is disabled" not in log.getvalue()
3154

3255

3356
@gen_test()
3457
async def test_bokeh_version_too_low():
3558
pytest.importorskip("bokeh")
3659

37-
with mock.patch.dict(sys.modules):
38-
# Remove these imports, so when the scheduler imports
39-
# `distributed.dashboard.scheduler`, it has to re-import `dashboard.core`, which
40-
# is where the bokeh version detection happens at import time, via
41-
# `dashboard.utils.BOKEH_VERSION`.
42-
sys.modules.pop("distributed.dashboard.scheduler", None)
43-
sys.modules.pop("distributed.dashboard.core", None)
44-
45-
with mock.patch("distributed.dashboard.utils.BOKEH_VERSION", Version("1.4.0")):
46-
with pytest.warns(UserWarning, match="1.4.0"):
47-
async with Scheduler(dashboard_address=":0") as s:
48-
http_client = AsyncHTTPClient()
49-
response = await http_client.fetch(
50-
f"http://localhost:{s.http_server.port}/status"
51-
)
52-
assert response.code == 200
53-
body = response.body.decode()
54-
assert "Dask needs bokeh" in body
60+
with captured_logger("distributed.scheduler") as log:
61+
with mock.patch.dict(sys.modules):
62+
# Remove these imports, so when the scheduler imports
63+
# `distributed.dashboard.scheduler`, it has to re-import `dashboard.core`, which
64+
# is where the bokeh version detection happens at import time, via
65+
# `dashboard.utils.BOKEH_VERSION`.
66+
sys.modules.pop("distributed.dashboard.scheduler", None)
67+
sys.modules.pop("distributed.dashboard.core", None)
68+
69+
with mock.patch(
70+
"distributed.dashboard.utils.BOKEH_VERSION", Version("1.4.0")
71+
):
72+
with pytest.warns(UserWarning, match="1.4.0"):
73+
async with Scheduler(dashboard=True, dashboard_address=":0") as s:
74+
http_client = AsyncHTTPClient()
75+
response = await http_client.fetch(
76+
f"http://localhost:{s.http_server.port}/status"
77+
)
78+
assert response.code == 200
79+
body = response.body.decode()
80+
assert "Dask needs bokeh" in body
81+
82+
assert "Dashboard is disabled" in log.getvalue()
83+
assert "bokeh>=3.1.0" in log.getvalue()
84+
assert "bokeh=1.4.0" in log.getvalue()
5585

5686

5787
@gen_test()
5888
async def test_bokeh_version_too_high():
5989
pytest.importorskip("bokeh")
6090

61-
with mock.patch.dict(sys.modules):
62-
sys.modules.pop("distributed.dashboard.scheduler", None)
63-
sys.modules.pop("distributed.dashboard.core", None)
64-
65-
with mock.patch("distributed.dashboard.utils.BOKEH_VERSION", Version("3.0.1")):
66-
with pytest.warns(UserWarning, match="3.0.1"):
67-
async with Scheduler(dashboard_address=":0") as s:
68-
http_client = AsyncHTTPClient()
69-
response = await http_client.fetch(
70-
f"http://localhost:{s.http_server.port}/status"
71-
)
72-
assert response.code == 200
73-
body = response.body.decode()
74-
assert "Dask needs bokeh" in body
91+
with captured_logger("distributed.scheduler") as log:
92+
with mock.patch.dict(sys.modules):
93+
sys.modules.pop("distributed.dashboard.scheduler", None)
94+
sys.modules.pop("distributed.dashboard.core", None)
95+
96+
with mock.patch(
97+
"distributed.dashboard.utils.BOKEH_VERSION", Version("3.0.1")
98+
):
99+
with pytest.warns(UserWarning, match="3.0.1"):
100+
async with Scheduler(dashboard=True, dashboard_address=":0") as s:
101+
http_client = AsyncHTTPClient()
102+
response = await http_client.fetch(
103+
f"http://localhost:{s.http_server.port}/status"
104+
)
105+
assert response.code == 200
106+
body = response.body.decode()
107+
assert "Dask needs bokeh" in body
108+
109+
assert "Dashboard is disabled" in log.getvalue()
110+
assert "bokeh>=3.1.0" in log.getvalue()
111+
assert "bokeh=3.0.1" in log.getvalue()

distributed/scheduler.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3992,14 +3992,22 @@ def __init__(
39923992
)
39933993

39943994
http_server_modules = dask.config.get("distributed.scheduler.http.routes")
3995+
explicit_dashboard_request = dashboard is True
39953996
show_dashboard = dashboard or (dashboard is None and dashboard_address)
39963997
# install vanilla route if show_dashboard but bokeh is not installed
39973998
if show_dashboard:
39983999
try:
39994000
import distributed.dashboard.scheduler
4000-
except ImportError:
4001+
except ImportError as e:
40014002
show_dashboard = False
40024003
http_server_modules.append("distributed.http.scheduler.missing_bokeh")
4004+
if explicit_dashboard_request:
4005+
logger.warning(
4006+
"Dashboard is disabled; the scheduler will serve a diagnostic "
4007+
"placeholder page instead. Explicit dashboard request could not "
4008+
"be satisfied because %s",
4009+
e,
4010+
)
40034011
routes = get_handlers(
40044012
server=self, modules=http_server_modules, prefix=http_prefix
40054013
)

0 commit comments

Comments
 (0)