diff --git a/gateway/platforms/feishu.py b/gateway/platforms/feishu.py index 718f01e9..7d25a227 100644 --- a/gateway/platforms/feishu.py +++ b/gateway/platforms/feishu.py @@ -141,6 +141,7 @@ from gateway.platforms.base import ( ) from gateway.status import acquire_scoped_lock, release_scoped_lock from hermes_constants import get_hermes_home +from utils import atomic_json_write logger = logging.getLogger(__name__) @@ -3804,7 +3805,7 @@ class FeishuAdapter(BasePlatformAdapter): recent = self._seen_message_order[-self._dedup_cache_size:] # Save as {msg_id: timestamp} so TTL filtering works across restarts. payload = {"message_ids": {k: self._seen_message_ids[k] for k in recent if k in self._seen_message_ids}} - self._dedup_state_path.write_text(json.dumps(payload, ensure_ascii=False), encoding="utf-8") + atomic_json_write(self._dedup_state_path, payload, indent=None) except OSError: logger.warning("[Feishu] Failed to persist dedup state to %s", self._dedup_state_path, exc_info=True) diff --git a/gateway/platforms/helpers.py b/gateway/platforms/helpers.py index 64aead4b..8db7af7e 100644 --- a/gateway/platforms/helpers.py +++ b/gateway/platforms/helpers.py @@ -13,6 +13,8 @@ import time from pathlib import Path from typing import TYPE_CHECKING, Dict +from utils import atomic_json_write + if TYPE_CHECKING: from gateway.platforms.base import MessageEvent @@ -237,12 +239,11 @@ class ThreadParticipationTracker: def _save(self) -> None: path = self._state_path() - path.parent.mkdir(parents=True, exist_ok=True) thread_list = list(self._threads) if len(thread_list) > self._max_tracked: thread_list = thread_list[-self._max_tracked:] self._threads = set(thread_list) - path.write_text(json.dumps(thread_list), encoding="utf-8") + atomic_json_write(path, thread_list, indent=None) def mark(self, thread_id: str) -> None: """Mark *thread_id* as participated and persist."""