From 3c21fed099727965fcb547bb9b263afe6b573cb0 Mon Sep 17 00:00:00 2001 From: Yuan Li Date: Sat, 23 May 2026 00:38:11 +0800 Subject: [PATCH] fix(bluebubbles): cap _guid_cache with LRU eviction to prevent unbounded growth The _guid_cache dict grows without bound as new contacts/groups are resolved. In a long-running gateway instance with many unique targets this becomes a slow memory leak. Replace the plain dict with an OrderedDict capped at 500 entries. When the cap is exceeded the oldest (least-recently-used) entries are evicted. --- gateway/platforms/bluebubbles.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/gateway/platforms/bluebubbles.py b/gateway/platforms/bluebubbles.py index ec852e3d610..f02adbbaa68 100644 --- a/gateway/platforms/bluebubbles.py +++ b/gateway/platforms/bluebubbles.py @@ -14,6 +14,7 @@ import logging import os import re import uuid +from collections import OrderedDict from datetime import datetime from typing import Any, Dict, List, Optional from urllib.parse import quote @@ -128,7 +129,8 @@ class BlueBubblesAdapter(BasePlatformAdapter): self._runner = None self._private_api_enabled: Optional[bool] = None self._helper_connected: bool = False - self._guid_cache: Dict[str, str] = {} + self._guid_cache: OrderedDict[str, str] = OrderedDict() + self._GUID_CACHE_MAX = 500 # ------------------------------------------------------------------ # API helpers @@ -365,6 +367,7 @@ class BlueBubblesAdapter(BasePlatformAdapter): if ";" in target: return target if target in self._guid_cache: + self._guid_cache.move_to_end(target) return self._guid_cache[target] try: payload = await self._api_post( @@ -377,10 +380,16 @@ class BlueBubblesAdapter(BasePlatformAdapter): if identifier == target: if guid: self._guid_cache[target] = guid + self._guid_cache.move_to_end(target) + if len(self._guid_cache) > self._GUID_CACHE_MAX: + self._guid_cache.popitem(last=False) return guid for part in chat.get("participants", []) or []: if (part.get("address") or "").strip() == target and guid: self._guid_cache[target] = guid + self._guid_cache.move_to_end(target) + if len(self._guid_cache) > self._GUID_CACHE_MAX: + self._guid_cache.popitem(last=False) return guid except Exception: pass