From f21d54acfaa0e5882a0df30a6c842ea5c515735f Mon Sep 17 00:00:00 2001 From: Joe Friedrichsen <114173023+jfriedri-ni@users.noreply.github.com> Date: Wed, 16 Jul 2025 14:46:27 -0700 Subject: [PATCH 1/8] Resolve the discovery service and use it as the base URL for the refresh component - Use the resolved URL when initializing the refresh component - Perform the resolution in PanelClient and expose it as a property Signed-off-by: Joe Friedrichsen <114173023+jfriedri-ni@users.noreply.github.com> --- src/nipanel/_panel_client.py | 72 ++++++++++++++++----- src/nipanel/_panel_value_accessor.py | 7 +- src/nipanel/_streamlit_constants.py | 1 - src/nipanel/_streamlit_panel_initializer.py | 3 +- src/nipanel/streamlit_refresh/__init__.py | 13 ++-- 5 files changed, 68 insertions(+), 28 deletions(-) diff --git a/src/nipanel/_panel_client.py b/src/nipanel/_panel_client.py index 278378e7..ae9e848b 100644 --- a/src/nipanel/_panel_client.py +++ b/src/nipanel/_panel_client.py @@ -15,7 +15,7 @@ SetValueRequest, ) from ni.pythonpanel.v1.python_panel_service_pb2_grpc import PythonPanelServiceStub -from ni_measurement_plugin_sdk_service.discovery import DiscoveryClient +from ni_measurement_plugin_sdk_service.discovery import DiscoveryClient, ServiceLocation from ni_measurement_plugin_sdk_service.grpc.channelpool import GrpcChannelPool from typing_extensions import ParamSpec @@ -57,8 +57,14 @@ def __init__( self._discovery_client = discovery_client self._grpc_channel_pool = grpc_channel_pool self._grpc_channel = grpc_channel + self._proxy_location: ServiceLocation | None = None self._stub: PythonPanelServiceStub | None = None + @property + def proxy_location(self) -> ServiceLocation: + """Return the ServiceLocation for the panel's proxy.""" + return self._get_proxy_location() + def start_panel(self, panel_id: str, panel_script_path: str, python_path: str) -> str: """Start the panel. @@ -134,29 +140,61 @@ def get_value(self, panel_id: str, value_id: str) -> tuple[bool, object]: else: return False, None + def _get_proxy_location(self) -> ServiceLocation: + if self._proxy_location is None: + self._proxy_location = self._resolve_discovery_service() + return self._proxy_location + def _get_stub(self) -> PythonPanelServiceStub: if self._stub is None: if self._grpc_channel is not None: self._stub = PythonPanelServiceStub(self._grpc_channel) else: - with self._initialization_lock: - if self._grpc_channel_pool is None: - _logger.debug("Creating unshared GrpcChannelPool.") - self._grpc_channel_pool = GrpcChannelPool() - if self._discovery_client is None: - _logger.debug("Creating unshared DiscoveryClient.") - self._discovery_client = DiscoveryClient( - grpc_channel_pool=self._grpc_channel_pool - ) - - service_location = self._discovery_client.resolve_service( - provided_interface=self._provided_interface, - service_class=self._service_class, - ) - channel = self._grpc_channel_pool.get_channel(service_location.insecure_address) - self._stub = PythonPanelServiceStub(channel) + channel = self._get_panel_service_channel() + self._stub = PythonPanelServiceStub(channel) return self._stub + def _get_grpc_channel_pool(self) -> GrpcChannelPool: + if self._grpc_channel_pool is None: + _logger.debug("Creating unshared GrpcChannelPool.") + self._grpc_channel_pool = GrpcChannelPool() + return self._grpc_channel_pool + + def _get_discovery_client(self, channel_pool: GrpcChannelPool) -> DiscoveryClient: + if self._discovery_client is None: + _logger.debug("Creating unshared DiscoveryClient.") + self._discovery_client = DiscoveryClient(grpc_channel_pool=channel_pool) + return self._discovery_client + + def _resolve_service( + self, discovery_client: DiscoveryClient, provided_interface: str, service_class: str = "" + ) -> ServiceLocation: + _logger.debug("Resolving '%s'.", provided_interface) + service_location = discovery_client.resolve_service( + provided_interface=provided_interface, + service_class=service_class, + ) + return service_location + + def _get_panel_service_channel(self) -> grpc.Channel: + with self._initialization_lock: + grpc_channel_pool = self._get_grpc_channel_pool() + discovery_client = self._get_discovery_client(grpc_channel_pool) + panel_location = self._resolve_service( + discovery_client, self._provided_interface, self._service_class + ) + channel = grpc_channel_pool.get_channel(panel_location.insecure_address) + return channel + + def _resolve_discovery_service(self) -> ServiceLocation: + with self._initialization_lock: + grpc_channel_pool = self._get_grpc_channel_pool() + discovery_client = self._get_discovery_client(grpc_channel_pool) + discovery_location = self._resolve_service( + discovery_client, provided_interface="ni.http1.proxy" + ) + return discovery_location + def _invoke_with_retry( self, method: Callable[_P, _T], *args: _P.args, **kwargs: _P.kwargs ) -> _T: diff --git a/src/nipanel/_panel_value_accessor.py b/src/nipanel/_panel_value_accessor.py index cb53d560..32fe2fbd 100644 --- a/src/nipanel/_panel_value_accessor.py +++ b/src/nipanel/_panel_value_accessor.py @@ -6,7 +6,7 @@ from typing import TypeVar, overload import grpc -from ni_measurement_plugin_sdk_service.discovery import DiscoveryClient +from ni_measurement_plugin_sdk_service.discovery import DiscoveryClient, ServiceLocation from ni_measurement_plugin_sdk_service.grpc.channelpool import GrpcChannelPool from nipanel._panel_client import PanelClient @@ -55,6 +55,11 @@ def panel_id(self) -> str: """Read-only accessor for the panel ID.""" return self._panel_id + @property + def proxy_location(self) -> ServiceLocation: + """Read-only accessor for the panel's proxy location.""" + return self._panel_client.proxy_location + @overload def get_value(self, value_id: str) -> object: ... diff --git a/src/nipanel/_streamlit_constants.py b/src/nipanel/_streamlit_constants.py index f1350c11..2cd9601e 100644 --- a/src/nipanel/_streamlit_constants.py +++ b/src/nipanel/_streamlit_constants.py @@ -1,2 +1 @@ STREAMLIT_PYTHON_PANEL_SERVICE = "ni.pythonpanel.v1.PythonPanelService" -STREAMLIT_REFRESH_COMPONENT_URL = "http://localhost:42001/panel-service/refresh" diff --git a/src/nipanel/_streamlit_panel_initializer.py b/src/nipanel/_streamlit_panel_initializer.py index a05822d0..19905ebe 100644 --- a/src/nipanel/_streamlit_panel_initializer.py +++ b/src/nipanel/_streamlit_panel_initializer.py @@ -63,7 +63,8 @@ def get_panel_accessor() -> StreamlitPanelValueAccessor: panel = cast(StreamlitPanelValueAccessor, st.session_state[PANEL_ACCESSOR_KEY]) _sync_session_state(panel) - refresh_component = initialize_refresh_component(panel.panel_id) + proxy_url = panel.proxy_location.insecure_address + refresh_component = initialize_refresh_component(proxy_url, panel.panel_id) refresh_component() return panel diff --git a/src/nipanel/streamlit_refresh/__init__.py b/src/nipanel/streamlit_refresh/__init__.py index ec9f1c5a..e79e9527 100644 --- a/src/nipanel/streamlit_refresh/__init__.py +++ b/src/nipanel/streamlit_refresh/__init__.py @@ -1,17 +1,14 @@ """Initializes a refresh component for Streamlit.""" -from typing import Any +from streamlit.components.v1 import declare_component +from streamlit.components.v1.custom_component import CustomComponent -import streamlit.components.v1 as components -from nipanel._streamlit_constants import STREAMLIT_REFRESH_COMPONENT_URL - - -def initialize_refresh_component(panel_id: str) -> Any: +def initialize_refresh_component(proxy_url: str, panel_id: str) -> CustomComponent: """Initialize a refresh component to the Streamlit app.""" - _refresh_component_func = components.declare_component( + _refresh_component_func = declare_component( "panelRefreshComponent", - url=f"{STREAMLIT_REFRESH_COMPONENT_URL}/{panel_id}", + url=f"http://{proxy_url}/panel-service/refresh/{panel_id}", ) return _refresh_component_func From 7af7a9b3bb60eeba15692fa405579b8d2f4ca74e Mon Sep 17 00:00:00 2001 From: Joe Friedrichsen <114173023+jfriedri-ni@users.noreply.github.com> Date: Thu, 17 Jul 2025 11:24:20 -0700 Subject: [PATCH 2/8] Revert the reuse of the discovery client Signed-off-by: Joe Friedrichsen <114173023+jfriedri-ni@users.noreply.github.com> --- src/nipanel/_panel_client.py | 72 +++++---------------- src/nipanel/_panel_value_accessor.py | 7 +- src/nipanel/_streamlit_panel_initializer.py | 3 +- src/nipanel/streamlit_refresh/__init__.py | 3 +- 4 files changed, 21 insertions(+), 64 deletions(-) diff --git a/src/nipanel/_panel_client.py b/src/nipanel/_panel_client.py index 8d28d905..9de42d3a 100644 --- a/src/nipanel/_panel_client.py +++ b/src/nipanel/_panel_client.py @@ -14,7 +14,7 @@ SetValueRequest, ) from ni.pythonpanel.v1.python_panel_service_pb2_grpc import PythonPanelServiceStub -from ni_measurement_plugin_sdk_service.discovery import DiscoveryClient, ServiceLocation +from ni_measurement_plugin_sdk_service.discovery import DiscoveryClient from ni_measurement_plugin_sdk_service.grpc.channelpool import GrpcChannelPool from typing_extensions import ParamSpec @@ -45,14 +45,8 @@ def __init__( self._discovery_client = discovery_client self._grpc_channel_pool = grpc_channel_pool self._grpc_channel = grpc_channel - self._proxy_location: ServiceLocation | None = None self._stub: PythonPanelServiceStub | None = None - @property - def proxy_location(self) -> ServiceLocation: - """Return the ServiceLocation for the panel's proxy.""" - return self._get_proxy_location() - def start_panel(self, panel_id: str, panel_script_path: str, python_path: str) -> str: start_panel_request = StartPanelRequest( panel_id=panel_id, panel_script_path=panel_script_path, python_path=python_path @@ -93,61 +87,29 @@ def try_get_value(self, panel_id: str, value_id: str) -> object | None: else: return None - def _get_proxy_location(self) -> ServiceLocation: - if self._proxy_location is None: - self._proxy_location = self._resolve_discovery_service() - return self._proxy_location - def _get_stub(self) -> PythonPanelServiceStub: if self._stub is None: if self._grpc_channel is not None: self._stub = PythonPanelServiceStub(self._grpc_channel) else: - channel = self._get_panel_service_channel() - self._stub = PythonPanelServiceStub(channel) + with self._initialization_lock: + if self._grpc_channel_pool is None: + _logger.debug("Creating unshared GrpcChannelPool.") + self._grpc_channel_pool = GrpcChannelPool() + if self._discovery_client is None: + _logger.debug("Creating unshared DiscoveryClient.") + self._discovery_client = DiscoveryClient( + grpc_channel_pool=self._grpc_channel_pool + ) + + service_location = self._discovery_client.resolve_service( + provided_interface=self._provided_interface, + service_class=self._service_class, + ) + channel = self._grpc_channel_pool.get_channel(service_location.insecure_address) + self._stub = PythonPanelServiceStub(channel) return self._stub - def _get_grpc_channel_pool(self) -> GrpcChannelPool: - if self._grpc_channel_pool is None: - _logger.debug("Creating unshared GrpcChannelPool.") - self._grpc_channel_pool = GrpcChannelPool() - return self._grpc_channel_pool - - def _get_discovery_client(self, channel_pool: GrpcChannelPool) -> DiscoveryClient: - if self._discovery_client is None: - _logger.debug("Creating unshared DiscoveryClient.") - self._discovery_client = DiscoveryClient(grpc_channel_pool=channel_pool) - return self._discovery_client - - def _resolve_service( - self, discovery_client: DiscoveryClient, provided_interface: str, service_class: str = "" - ) -> ServiceLocation: - _logger.debug("Resolving '%s'.", provided_interface) - service_location = discovery_client.resolve_service( - provided_interface=provided_interface, - service_class=service_class, - ) - return service_location - - def _get_panel_service_channel(self) -> grpc.Channel: - with self._initialization_lock: - grpc_channel_pool = self._get_grpc_channel_pool() - discovery_client = self._get_discovery_client(grpc_channel_pool) - panel_location = self._resolve_service( - discovery_client, self._provided_interface, self._service_class - ) - channel = grpc_channel_pool.get_channel(panel_location.insecure_address) - return channel - - def _resolve_discovery_service(self) -> ServiceLocation: - with self._initialization_lock: - grpc_channel_pool = self._get_grpc_channel_pool() - discovery_client = self._get_discovery_client(grpc_channel_pool) - discovery_location = self._resolve_service( - discovery_client, provided_interface="ni.http1.proxy" - ) - return discovery_location - def _invoke_with_retry( self, method: Callable[_P, _T], *args: _P.args, **kwargs: _P.kwargs ) -> _T: diff --git a/src/nipanel/_panel_value_accessor.py b/src/nipanel/_panel_value_accessor.py index 630b7fad..c123bd0f 100644 --- a/src/nipanel/_panel_value_accessor.py +++ b/src/nipanel/_panel_value_accessor.py @@ -6,7 +6,7 @@ from typing import TypeVar, overload import grpc -from ni_measurement_plugin_sdk_service.discovery import DiscoveryClient, ServiceLocation +from ni_measurement_plugin_sdk_service.discovery import DiscoveryClient from ni_measurement_plugin_sdk_service.grpc.channelpool import GrpcChannelPool from nipanel._panel_client import _PanelClient @@ -55,11 +55,6 @@ def panel_id(self) -> str: """Read-only accessor for the panel ID.""" return self._panel_id - @property - def proxy_location(self) -> ServiceLocation: - """Read-only accessor for the panel's proxy location.""" - return self._panel_client.proxy_location - @overload def get_value(self, value_id: str) -> object: ... diff --git a/src/nipanel/_streamlit_panel_initializer.py b/src/nipanel/_streamlit_panel_initializer.py index 19905ebe..a05822d0 100644 --- a/src/nipanel/_streamlit_panel_initializer.py +++ b/src/nipanel/_streamlit_panel_initializer.py @@ -63,8 +63,7 @@ def get_panel_accessor() -> StreamlitPanelValueAccessor: panel = cast(StreamlitPanelValueAccessor, st.session_state[PANEL_ACCESSOR_KEY]) _sync_session_state(panel) - proxy_url = panel.proxy_location.insecure_address - refresh_component = initialize_refresh_component(proxy_url, panel.panel_id) + refresh_component = initialize_refresh_component(panel.panel_id) refresh_component() return panel diff --git a/src/nipanel/streamlit_refresh/__init__.py b/src/nipanel/streamlit_refresh/__init__.py index e79e9527..2699bbd1 100644 --- a/src/nipanel/streamlit_refresh/__init__.py +++ b/src/nipanel/streamlit_refresh/__init__.py @@ -4,8 +4,9 @@ from streamlit.components.v1.custom_component import CustomComponent -def initialize_refresh_component(proxy_url: str, panel_id: str) -> CustomComponent: +def initialize_refresh_component(panel_id: str) -> CustomComponent: """Initialize a refresh component to the Streamlit app.""" + proxy_url = "TODO" _refresh_component_func = declare_component( "panelRefreshComponent", url=f"http://{proxy_url}/panel-service/refresh/{panel_id}", From 88c7216e8fc47dfe809ec73b9cb1d9940f70e135 Mon Sep 17 00:00:00 2001 From: Joe Friedrichsen <114173023+jfriedri-ni@users.noreply.github.com> Date: Fri, 18 Jul 2025 11:19:13 -0700 Subject: [PATCH 3/8] Resolve the proxy separately for refresh component Signed-off-by: Joe Friedrichsen <114173023+jfriedri-ni@users.noreply.github.com> --- src/nipanel/streamlit_refresh/__init__.py | 26 +++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/nipanel/streamlit_refresh/__init__.py b/src/nipanel/streamlit_refresh/__init__.py index 2699bbd1..fdb31baa 100644 --- a/src/nipanel/streamlit_refresh/__init__.py +++ b/src/nipanel/streamlit_refresh/__init__.py @@ -1,15 +1,37 @@ """Initializes a refresh component for Streamlit.""" +from typing import ClassVar + +from ni_measurement_plugin_sdk_service.discovery import DiscoveryClient +from ni_measurement_plugin_sdk_service.grpc.channelpool import GrpcChannelPool from streamlit.components.v1 import declare_component from streamlit.components.v1.custom_component import CustomComponent +class _ServiceResolver: + + _panel_service_proxy_location: ClassVar[str | None] = None + + @classmethod + def get_or_resolve_proxy(cls) -> str: + if cls._panel_service_proxy_location is None: + discovery_client = DiscoveryClient(grpc_channel_pool=GrpcChannelPool()) + service_location = discovery_client.resolve_service( + provided_interface="ni.http1.proxy", + service_class="", + ) + cls._panel_service_proxy_location = service_location.insecure_address + + return cls._panel_service_proxy_location + + def initialize_refresh_component(panel_id: str) -> CustomComponent: """Initialize a refresh component to the Streamlit app.""" - proxy_url = "TODO" + proxy_base_address = _ServiceResolver.get_or_resolve_proxy() + component_url = f"http://{proxy_base_address}/panel-service/refresh/{panel_id}" _refresh_component_func = declare_component( "panelRefreshComponent", - url=f"http://{proxy_url}/panel-service/refresh/{panel_id}", + url=component_url, ) return _refresh_component_func From 7e765824a472e2a0a545482a53b25f2fa45bc950 Mon Sep 17 00:00:00 2001 From: Joe Friedrichsen <114173023+jfriedri-ni@users.noreply.github.com> Date: Fri, 18 Jul 2025 12:01:27 -0700 Subject: [PATCH 4/8] Use __future__ to support py3.11 style type hints Signed-off-by: Joe Friedrichsen <114173023+jfriedri-ni@users.noreply.github.com> --- src/nipanel/streamlit_refresh/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/nipanel/streamlit_refresh/__init__.py b/src/nipanel/streamlit_refresh/__init__.py index fdb31baa..13ecfcf3 100644 --- a/src/nipanel/streamlit_refresh/__init__.py +++ b/src/nipanel/streamlit_refresh/__init__.py @@ -1,5 +1,7 @@ """Initializes a refresh component for Streamlit.""" +from __future__ import annotations + from typing import ClassVar from ni_measurement_plugin_sdk_service.discovery import DiscoveryClient From 0f41a19f716440dc61b4d046fd736446d87c0eb9 Mon Sep 17 00:00:00 2001 From: Joe Friedrichsen <114173023+jfriedri-ni@users.noreply.github.com> Date: Fri, 18 Jul 2025 12:56:51 -0700 Subject: [PATCH 5/8] Rework service resolution to use a global Signed-off-by: Joe Friedrichsen <114173023+jfriedri-ni@users.noreply.github.com> --- src/nipanel/streamlit_refresh/__init__.py | 33 +++++++++++------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/src/nipanel/streamlit_refresh/__init__.py b/src/nipanel/streamlit_refresh/__init__.py index 13ecfcf3..22d996d5 100644 --- a/src/nipanel/streamlit_refresh/__init__.py +++ b/src/nipanel/streamlit_refresh/__init__.py @@ -2,34 +2,18 @@ from __future__ import annotations -from typing import ClassVar - from ni_measurement_plugin_sdk_service.discovery import DiscoveryClient from ni_measurement_plugin_sdk_service.grpc.channelpool import GrpcChannelPool from streamlit.components.v1 import declare_component from streamlit.components.v1.custom_component import CustomComponent -class _ServiceResolver: - - _panel_service_proxy_location: ClassVar[str | None] = None - - @classmethod - def get_or_resolve_proxy(cls) -> str: - if cls._panel_service_proxy_location is None: - discovery_client = DiscoveryClient(grpc_channel_pool=GrpcChannelPool()) - service_location = discovery_client.resolve_service( - provided_interface="ni.http1.proxy", - service_class="", - ) - cls._panel_service_proxy_location = service_location.insecure_address - - return cls._panel_service_proxy_location +_panel_service_proxy_location: str | None = None def initialize_refresh_component(panel_id: str) -> CustomComponent: """Initialize a refresh component to the Streamlit app.""" - proxy_base_address = _ServiceResolver.get_or_resolve_proxy() + proxy_base_address = _get_or_resolve_proxy() component_url = f"http://{proxy_base_address}/panel-service/refresh/{panel_id}" _refresh_component_func = declare_component( "panelRefreshComponent", @@ -37,3 +21,16 @@ def initialize_refresh_component(panel_id: str) -> CustomComponent: ) return _refresh_component_func + + +def _get_or_resolve_proxy() -> str: + global _panel_service_proxy_location + if _panel_service_proxy_location is None: + discovery_client = DiscoveryClient(grpc_channel_pool=GrpcChannelPool()) + service_location = discovery_client.resolve_service( + provided_interface="ni.http1.proxy", + service_class="", + ) + _panel_service_proxy_location = service_location.insecure_address + + return _panel_service_proxy_location From 058ca3f666c8247aac8d671bb9424bbc5336853f Mon Sep 17 00:00:00 2001 From: Joe Friedrichsen <114173023+jfriedri-ni@users.noreply.github.com> Date: Fri, 18 Jul 2025 13:05:52 -0700 Subject: [PATCH 6/8] Add thread safety and explicit lifetimes for system resources Signed-off-by: Joe Friedrichsen <114173023+jfriedri-ni@users.noreply.github.com> --- src/nipanel/streamlit_refresh/__init__.py | 24 +++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/nipanel/streamlit_refresh/__init__.py b/src/nipanel/streamlit_refresh/__init__.py index 22d996d5..b844390f 100644 --- a/src/nipanel/streamlit_refresh/__init__.py +++ b/src/nipanel/streamlit_refresh/__init__.py @@ -2,6 +2,8 @@ from __future__ import annotations +import threading + from ni_measurement_plugin_sdk_service.discovery import DiscoveryClient from ni_measurement_plugin_sdk_service.grpc.channelpool import GrpcChannelPool from streamlit.components.v1 import declare_component @@ -24,13 +26,15 @@ def initialize_refresh_component(panel_id: str) -> CustomComponent: def _get_or_resolve_proxy() -> str: - global _panel_service_proxy_location - if _panel_service_proxy_location is None: - discovery_client = DiscoveryClient(grpc_channel_pool=GrpcChannelPool()) - service_location = discovery_client.resolve_service( - provided_interface="ni.http1.proxy", - service_class="", - ) - _panel_service_proxy_location = service_location.insecure_address - - return _panel_service_proxy_location + with threading.RLock(): + global _panel_service_proxy_location + if _panel_service_proxy_location is None: + with GrpcChannelPool() as grpc_channel_pool: + discovery_client = DiscoveryClient(grpc_channel_pool=grpc_channel_pool) + service_location = discovery_client.resolve_service( + provided_interface="ni.http1.proxy", + service_class="", + ) + _panel_service_proxy_location = service_location.insecure_address + + return _panel_service_proxy_location From 0cdf51caf3d39ba0b64bf127ae448bd41542e5db Mon Sep 17 00:00:00 2001 From: Joe Friedrichsen <114173023+jfriedri-ni@users.noreply.github.com> Date: Fri, 18 Jul 2025 14:54:38 -0700 Subject: [PATCH 7/8] Use a single lock instance so access is exclusive Signed-off-by: Joe Friedrichsen <114173023+jfriedri-ni@users.noreply.github.com> --- src/nipanel/streamlit_refresh/__init__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/nipanel/streamlit_refresh/__init__.py b/src/nipanel/streamlit_refresh/__init__.py index b844390f..2683f9e3 100644 --- a/src/nipanel/streamlit_refresh/__init__.py +++ b/src/nipanel/streamlit_refresh/__init__.py @@ -10,6 +10,7 @@ from streamlit.components.v1.custom_component import CustomComponent +_grpc_client_lock = threading.RLock() _panel_service_proxy_location: str | None = None @@ -26,7 +27,8 @@ def initialize_refresh_component(panel_id: str) -> CustomComponent: def _get_or_resolve_proxy() -> str: - with threading.RLock(): + global _grpc_client_lock + with _grpc_client_lock: global _panel_service_proxy_location if _panel_service_proxy_location is None: with GrpcChannelPool() as grpc_channel_pool: From acb1a58efeb647148daabb9606b9baa7574495a6 Mon Sep 17 00:00:00 2001 From: Joe F <114173023+jfriedri-ni@users.noreply.github.com> Date: Fri, 18 Jul 2025 15:03:21 -0700 Subject: [PATCH 8/8] No need to use global for the lock Co-authored-by: Brad Keryan --- src/nipanel/streamlit_refresh/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/nipanel/streamlit_refresh/__init__.py b/src/nipanel/streamlit_refresh/__init__.py index 2683f9e3..72c35ac0 100644 --- a/src/nipanel/streamlit_refresh/__init__.py +++ b/src/nipanel/streamlit_refresh/__init__.py @@ -27,7 +27,6 @@ def initialize_refresh_component(panel_id: str) -> CustomComponent: def _get_or_resolve_proxy() -> str: - global _grpc_client_lock with _grpc_client_lock: global _panel_service_proxy_location if _panel_service_proxy_location is None: