feat(handler): 添加消息去重功能防止飞书重复投递
实现基于(user_id, content)的消息去重机制,避免飞书在网络抖动时重复投递相同消息。使用10秒时间窗口判断重复消息,超过窗口的旧记录会被自动清理。
This commit is contained in:
parent
cbeafa35a5
commit
d6183594d6
@ -25,6 +25,26 @@ _ws_connected: bool = False
|
|||||||
_last_message_time: float = 0.0
|
_last_message_time: float = 0.0
|
||||||
_reconnect_count: int = 0
|
_reconnect_count: int = 0
|
||||||
|
|
||||||
|
# Deduplication: drop Feishu re-deliveries by (user_id, content) within a short window.
|
||||||
|
# Feishu retries on network hiccups within ~60s using the same payload.
|
||||||
|
# We use a 10s window: identical content from the same user within 10s is a re-delivery,
|
||||||
|
# not a deliberate repeat (user intentional repeats arrive after the bot has already replied).
|
||||||
|
_recent_messages: dict[tuple[str, str], float] = {} # key: (user_id, content) → timestamp
|
||||||
|
_DEDUP_WINDOW = 10.0 # seconds
|
||||||
|
|
||||||
|
|
||||||
|
def _is_duplicate(user_id: str, content: str) -> bool:
|
||||||
|
"""Return True if this (user, content) pair arrived within the dedup window."""
|
||||||
|
now = time.time()
|
||||||
|
expired = [k for k, ts in _recent_messages.items() if now - ts > _DEDUP_WINDOW]
|
||||||
|
for k in expired:
|
||||||
|
del _recent_messages[k]
|
||||||
|
key = (user_id, content)
|
||||||
|
if key in _recent_messages:
|
||||||
|
return True
|
||||||
|
_recent_messages[key] = now
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def get_ws_status() -> dict[str, Any]:
|
def get_ws_status() -> dict[str, Any]:
|
||||||
"""Return WebSocket connection status."""
|
"""Return WebSocket connection status."""
|
||||||
@ -79,10 +99,14 @@ def _handle_message(data: P2ImMessageReceiveV1) -> None:
|
|||||||
logger.info("Empty text after stripping, ignoring")
|
logger.info("Empty text after stripping, ignoring")
|
||||||
return
|
return
|
||||||
|
|
||||||
logger.info("✉ ...%s → %r", open_id[-8:], text[:80])
|
|
||||||
|
|
||||||
user_id = open_id or chat_id
|
user_id = open_id or chat_id
|
||||||
|
|
||||||
|
if _is_duplicate(user_id, text):
|
||||||
|
logger.info("Dropping duplicate delivery: user=...%s text=%r", user_id[-8:], text[:60])
|
||||||
|
return
|
||||||
|
|
||||||
|
logger.info("✉ ...%s → %r", open_id[-8:], text[:80])
|
||||||
|
|
||||||
if _main_loop is None:
|
if _main_loop is None:
|
||||||
logger.error("Main event loop not set; cannot process message")
|
logger.error("Main event loop not set; cannot process message")
|
||||||
return
|
return
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user