From 2406e5348d131b3f0a101e1e3ff2928bea1dec0c Mon Sep 17 00:00:00 2001 From: ktanaka85 Date: Wed, 26 Aug 2026 16:03:48 +0900 Subject: [PATCH 1/5] =?UTF-8?q?=E8=A7=A3=E6=9E=90=E7=92=B0=E5=A2=83?= =?UTF-8?q?=E6=95=B0=E3=81=AE=E8=A1=A8=E7=A4=BA=E3=81=A8https://jupyter.cs?= =?UTF-8?q?.rcos.nii.ac.jp/=E3=81=AE=E3=83=AA=E3=83=B3=E3=82=AF=E3=82=92?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- binderhub/launcher.py | 8 +++++++ binderhub/main.py | 21 ++++++++++++++++--- .../static/js/components/LinkGenerator.jsx | 12 +++++++++++ helm-chart/binderhub/Chart.yaml | 2 +- 4 files changed, 39 insertions(+), 4 deletions(-) diff --git a/binderhub/launcher.py b/binderhub/launcher.py index 8d7b81fbe..2e5e230b5 100644 --- a/binderhub/launcher.py +++ b/binderhub/launcher.py @@ -148,6 +148,14 @@ async def get_user_data(self, username): body = json.loads(resp.body.decode("utf-8")) return body + async def get_named_server_count(self, username): + """Return the number of named servers for a given JupyterHub user.""" + user_data = await self.get_user_data(username) + servers = user_data.get("servers", {}) + if not isinstance(servers, dict): + return 0 + return sum(1 for server_name in servers if server_name != "") + def unique_name_from_repo(self, repo_url): """Generate a unique name for a git repo url diff --git a/binderhub/main.py b/binderhub/main.py index 357e2bef4..570075b79 100644 --- a/binderhub/main.py +++ b/binderhub/main.py @@ -23,17 +23,32 @@ def initialize(self): return super().initialize() @authenticated - def get(self): + async def get(self): repoproviders_display_config = [ repo_provider_class.display_config for repo_provider_class in self.settings["repo_providers"].values() ] + running_environment_count = None + launcher = self.settings.get("launcher") + if launcher is not None: + try: + user = self.get_current_user() + username = user.get("name") if isinstance(user, dict) else user + if username: + running_environment_count = await launcher.get_named_server_count( + username + ) + except Exception: + self.log.debug( + "Unable to determine current environment count", exc_info=True + ) self.page_config |= { "baseUrl": self.settings["base_url"], "badgeBaseUrl": self.get_badge_base_url(), "logoUrl": self.static_url("logo.svg"), "logoWidth": "320px", "repoProviders": repoproviders_display_config, + "runningEnvironmentCount": running_environment_count, "aboutMessage": self.settings["about_message"], "bannerHtml": self.settings["banner_message"], "binderVersion": binder_version, @@ -58,7 +73,7 @@ def initialize(self, repo_provider): return super().initialize() @authenticated - def get(self, provider_id, _escaped_spec): + async def get(self, provider_id, _escaped_spec): prefix = "/v2/" + provider_id spec = self.get_spec_from_request(prefix) @@ -75,7 +90,7 @@ def get(self, provider_id, _escaped_spec): self.opengraph_title = ( f"{self.repo_provider.display_config['displayName']}: {spec}" ) - return super().get() + return await super().get() class LegacyRedirectHandler(BaseHandler): diff --git a/binderhub/static/js/components/LinkGenerator.jsx b/binderhub/static/js/components/LinkGenerator.jsx index 7492ee08d..439b03587 100644 --- a/binderhub/static/js/components/LinkGenerator.jsx +++ b/binderhub/static/js/components/LinkGenerator.jsx @@ -1,5 +1,6 @@ import { useEffect, useState } from "react"; import copy from "copy-to-clipboard"; +import { PAGE_CONFIG } from "../App.jsx"; /** * @typedef {object} ProviderSelectorProps @@ -346,6 +347,17 @@ export function LinkGenerator({ →問い合わせ先/エラーが発生したときは
Contact Information/Troubleshooting + {PAGE_CONFIG.runningEnvironmentCount !== undefined && + PAGE_CONFIG.runningEnvironmentCount !== null && ( +
+ + あなたは {PAGE_CONFIG.runningEnvironmentCount}個の解析環境を持っています + + {PAGE_CONFIG.runningEnvironmentCount >= 10 && ( + <>
解析環境の数が上限に達しています + )} +
+ )} ); } diff --git a/helm-chart/binderhub/Chart.yaml b/helm-chart/binderhub/Chart.yaml index a6fe67e0c..3a28f1dbb 100644 --- a/helm-chart/binderhub/Chart.yaml +++ b/helm-chart/binderhub/Chart.yaml @@ -1,7 +1,7 @@ # Chart.yaml v2 reference: https://helm.sh/docs/topics/charts/#the-chartyaml-file apiVersion: v2 name: binderhub -version: 0.2.5-20260304.3 +version: 0.2.5-20260826 dependencies: # Source code: https://github.com/jupyterhub/zero-to-jupyterhub-k8s # Latest version: https://github.com/jupyterhub/zero-to-jupyterhub-k8s/tags From afa3510e3f909779818fad86ef85fd342cafd336 Mon Sep 17 00:00:00 2001 From: ktanaka85 Date: Wed, 26 Aug 2026 17:03:07 +0900 Subject: [PATCH 2/5] =?UTF-8?q?api=5Frequest=E6=99=82=E3=81=AE=E3=83=AA?= =?UTF-8?q?=E3=83=88=E3=83=A9=E3=82=A4=E3=82=A8=E3=83=A9=E3=83=BC=E3=82=B3?= =?UTF-8?q?=E3=83=BC=E3=83=89=E3=81=AE=E3=83=91=E3=82=BF=E3=83=BC=E3=83=B3?= =?UTF-8?q?=E3=82=92=E8=BF=BD=E5=8A=A0(=E3=83=9A=E3=83=BC=E3=82=B8GET?= =?UTF-8?q?=E6=99=82=E3=81=ABapi=5Frequest=E3=82=92=E5=AE=9F=E6=96=BD?= =?UTF-8?q?=E3=81=99=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB=E3=81=AA=E3=82=8B?= =?UTF-8?q?=E3=81=9F=E3=82=81=E3=80=81=E8=87=AA=E5=8B=95=E3=83=86=E3=82=B9?= =?UTF-8?q?=E3=83=88=E7=AD=89jupyterhub=E3=81=AE=E8=B5=B7=E5=8B=95?= =?UTF-8?q?=E3=81=BE=E3=81=8C=E9=96=93=E3=81=AB=E5=90=88=E3=82=8F=E3=81=AA?= =?UTF-8?q?=E3=81=84=E3=82=B1=E3=83=BC=E3=82=B9=E3=81=AB=E5=AF=BE=E5=BF=9C?= =?UTF-8?q?=E3=81=99=E3=82=8B=E3=81=9F=E3=82=81)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- binderhub/launcher.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/binderhub/launcher.py b/binderhub/launcher.py index 2e5e230b5..1347cb67e 100644 --- a/binderhub/launcher.py +++ b/binderhub/launcher.py @@ -124,7 +124,7 @@ async def api_request(self, url, *args, **kwargs): # because they are likely intermittent issues in the cluster # e.g. 502,504 due to ingress issues or Hub relocating, # 599 due to connection issues such as Hub restarting - if e.code >= 500: + if e.code >= 500 or e.code in (403, 404): self.log.error( "Error accessing Hub API (using %s): %s", request_url, e ) From eb8165973ae60b230df2aa66b638757df91d589a Mon Sep 17 00:00:00 2001 From: ktanaka85 Date: Wed, 26 Aug 2026 17:22:01 +0900 Subject: [PATCH 3/5] =?UTF-8?q?API=E6=8E=A5=E7=B6=9A=E3=82=A8=E3=83=A9?= =?UTF-8?q?=E3=83=BC=E6=99=82=E3=81=AB=E7=94=BB=E9=9D=A2=E6=8F=8F=E7=94=BB?= =?UTF-8?q?=E3=82=92=E6=90=8D=E3=81=AA=E3=82=8F=E3=81=AA=E3=81=84=E3=82=88?= =?UTF-8?q?=E3=81=86=E3=81=AB=E3=82=A8=E3=83=A9=E3=83=BC=E3=83=8F=E3=83=B3?= =?UTF-8?q?=E3=83=89=E3=83=AA=E3=83=B3=E3=82=B0=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- binderhub/launcher.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/binderhub/launcher.py b/binderhub/launcher.py index 1347cb67e..9fa517415 100644 --- a/binderhub/launcher.py +++ b/binderhub/launcher.py @@ -150,7 +150,10 @@ async def get_user_data(self, username): async def get_named_server_count(self, username): """Return the number of named servers for a given JupyterHub user.""" - user_data = await self.get_user_data(username) + try: + user_data = await self.get_user_data(username) + except RuntimeError: + return 0 servers = user_data.get("servers", {}) if not isinstance(servers, dict): return 0 From c0e951894820c5dc39362d845460a50e78c61055 Mon Sep 17 00:00:00 2001 From: ktanaka85 Date: Thu, 27 Aug 2026 09:15:32 +0900 Subject: [PATCH 4/5] =?UTF-8?q?UI=E3=83=86=E3=82=B9=E3=83=88=E3=81=AE?= =?UTF-8?q?=E5=BF=9C=E7=AD=94=E5=BE=85=E3=81=A1=E6=99=82=E9=96=93=E3=82=92?= =?UTF-8?q?=E5=BB=B6=E9=95=B7,launcher.py=E3=81=AE=E3=82=A8=E3=83=A9?= =?UTF-8?q?=E3=83=BC=E3=82=B3=E3=83=BC=E3=83=89=E5=88=A4=E5=AE=9A=E3=82=92?= =?UTF-8?q?=E5=85=83=E3=81=AB=E6=88=BB=E3=81=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- binderhub/launcher.py | 2 +- integration-tests/test_ui.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/binderhub/launcher.py b/binderhub/launcher.py index 9fa517415..a6f0cd423 100644 --- a/binderhub/launcher.py +++ b/binderhub/launcher.py @@ -124,7 +124,7 @@ async def api_request(self, url, *args, **kwargs): # because they are likely intermittent issues in the cluster # e.g. 502,504 due to ingress issues or Hub relocating, # 599 due to connection issues such as Hub restarting - if e.code >= 500 or e.code in (403, 404): + if e.code >= 500: self.log.error( "Error accessing Hub API (using %s): %s", request_url, e ) diff --git a/integration-tests/test_ui.py b/integration-tests/test_ui.py index 4b0215098..36c5a67d5 100644 --- a/integration-tests/test_ui.py +++ b/integration-tests/test_ui.py @@ -35,7 +35,7 @@ async def local_hub_local_binder(request): ) url = f"http://127.0.0.1:{port}/services/binder/" - for i in range(10): + for i in range(30): try: resp = await async_requests.get(url) if resp.status_code == 200: From 4068fd2be97162410080cc1d853a534f78a24f19 Mon Sep 17 00:00:00 2001 From: ktanaka85 Date: Thu, 27 Aug 2026 09:38:38 +0900 Subject: [PATCH 5/5] =?UTF-8?q?binderhug=E3=81=AEChart.yaml=E3=81=AE?= =?UTF-8?q?=E3=83=90=E3=83=BC=E3=82=B8=E3=83=A7=E3=83=B3=E3=82=BF=E3=82=B0?= =?UTF-8?q?=E3=82=92=E6=9C=80=E6=96=B0=E5=8C=96(0.2.5-20260827)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- helm-chart/binderhub/Chart.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helm-chart/binderhub/Chart.yaml b/helm-chart/binderhub/Chart.yaml index 3a28f1dbb..ba1f13453 100644 --- a/helm-chart/binderhub/Chart.yaml +++ b/helm-chart/binderhub/Chart.yaml @@ -1,7 +1,7 @@ # Chart.yaml v2 reference: https://helm.sh/docs/topics/charts/#the-chartyaml-file apiVersion: v2 name: binderhub -version: 0.2.5-20260826 +version: 0.2.5-20260827 dependencies: # Source code: https://github.com/jupyterhub/zero-to-jupyterhub-k8s # Latest version: https://github.com/jupyterhub/zero-to-jupyterhub-k8s/tags