From 9d5d8ce0b25e1bbc932b4ce25004d07e50af06f3 Mon Sep 17 00:00:00 2001 From: EloquentBrush <147827411+EloquentBrush@users.noreply.github.com> Date: Wed, 22 Jul 2026 08:03:36 -0700 Subject: [PATCH] fix(slack): cap _user_name_cache to prevent unbounded growth MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit _resolve_user_name() caches every resolved (team_id, user_id) → display name but never evicts entries. On a long-running bot in a large workspace every unique user the bot encounters adds a permanent entry. Sibling structures _bot_message_ts (BOT_TS_MAX=5000) and _assistant_threads (ASSISTANT_THREADS_MAX=5000) already have caps; _user_name_cache had none. Fix: add _USER_NAME_CACHE_MAX = 5000 and evict the oldest half on overflow after each write, matching the existing sibling pattern. Consolidates the two cache-write branches (success + API error) into a single write so eviction runs once per resolution. Reapplied from #23676 onto the current adapter (cache moved to plugins/platforms/slack/adapter.py and is now keyed by (team_id, user_id) tuples for multi-workspace safety). --- plugins/platforms/slack/adapter.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/plugins/platforms/slack/adapter.py b/plugins/platforms/slack/adapter.py index 0e24ffc46036..28c29a828156 100644 --- a/plugins/platforms/slack/adapter.py +++ b/plugins/platforms/slack/adapter.py @@ -675,6 +675,7 @@ class SlackAdapter(BasePlatformAdapter): # so a multi-workspace Socket Mode process never reuses another # tenant's display name. self._user_name_cache: Dict[Tuple[str, str], str] = {} + self._USER_NAME_CACHE_MAX = 5000 self._socket_mode_task: Optional[asyncio.Task] = None # Multi-workspace support self._team_clients: Dict[str, Any] = {} # team_id → WebClient @@ -2763,12 +2764,16 @@ class SlackAdapter(BasePlatformAdapter): or user.get("name") or user_id ) - self._user_name_cache[cache_key] = name - return name except Exception as e: logger.debug("[Slack] users.info failed for %s: %s", user_id, e) - self._user_name_cache[cache_key] = user_id - return user_id + name = user_id + + self._user_name_cache[cache_key] = name + if len(self._user_name_cache) > self._USER_NAME_CACHE_MAX: + excess = len(self._user_name_cache) - self._USER_NAME_CACHE_MAX // 2 + for old_key in list(self._user_name_cache)[:excess]: + del self._user_name_cache[old_key] + return name async def _humanize_user_mentions( self, text: str, chat_id: str = "", team_id: str = ""