You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

遵循SOLID原则,客户端如何处理无序服务端交互及请求响应关联?

基于SOLID原则的异步WebSocket客户端设计方案(Discord Bot重构)

核心需求梳理

  • 异步WebSocket通信:处理Get/GetDataPackage请求的乱序响应(通过Retrieved消息的key关联请求)
  • 兼容服务器主动推送的PrintJSON/RoomUpdate等消息,确保无丢失
  • 启动阶段批量同步数据,跟踪大量待处理请求
  • 严格遵循SOLID设计原则

遵循SOLID原则的模块拆分与设计思路

1. 单一职责原则:拆分独立业务模块

将不同职责解耦为独立组件,避免单体耦合:

  • 请求管理器:仅负责请求的创建、待处理请求跟踪、响应与请求的匹配关联
  • 消息处理器集群:按消息类型拆分,一类处理请求对应的Retrieved响应,一类处理服务器主动推送的消息
  • WebSocket适配器:仅封装底层WebSocket的连接、发送、接收逻辑,不介入业务处理
  • Discord适配器:仅处理Discord侧的交互逻辑,与服务器通信逻辑完全隔离

2. 开放封闭原则:可扩展的消息处理机制

采用策略模式实现消息的可扩展处理:

  • 定义抽象的MessageHandler接口,所有消息类型(Retrieved/PrintJSON/RoomUpdate)对应独立的实现类
  • 维护一个消息处理器注册表,收到消息后根据类型分发到对应处理器;新增消息类型只需添加新的实现类,无需修改现有核心代码

3. 里氏替换原则:统一请求/响应抽象

  • 定义抽象BaseRequest基类,所有请求(Get/GetDataPackage)继承该类,包含唯一标识(如协议指定的key)、请求类型、异步回调逻辑
  • 定义抽象BaseMessage基类,覆盖所有响应与推送消息,包含消息类型、关联标识(如Retrieved的key)

4. 接口隔离原则:细粒度接口拆分

  • 为WebSocket适配器拆分WebSocketSender和WebSocketReceiver接口,分别负责消息发送与接收,避免组件依赖不需要的方法
  • 为请求管理器拆分RequestTracker和RequestMatcher接口,分别负责待处理请求的跟踪与响应匹配

5. 依赖倒置原则:面向抽象编程

  • 消息处理器依赖抽象的BaseMessage接口,而非具体的WebSocket消息格式
  • 请求管理器依赖抽象的BaseRequest和BaseMessage接口,而非具体的Get请求或Retrieved响应实现

核心功能实现细节

待处理请求跟踪与响应关联

  • 使用异步安全字典(结合asyncio.Lock保护普通字典,或使用aiodict)存储待处理请求:key为请求的key,value为asyncio.Future对象(用于异步等待响应)
  • 发送请求流程:生成唯一key → 创建Future并存入字典 → 发送WebSocket消息
  • 响应匹配流程:收到Retrieved消息后,提取key → 从字典中取出对应Future → 设置Future结果,完成异步等待
  • 超时处理:为每个Future设置超时时间,超时后自动从字典移除并触发错误回调

服务器主动推送消息的处理

  • WebSocket接收器收到消息后,先判断是否为带key的响应消息:
    • 若是响应消息,转发给RetrievedHandler处理关联逻辑
    • 若为主动推送消息(无对应请求key),直接分发到对应处理器(如PrintJSONHandler/RoomUpdateHandler)
  • 使用异步队列(asyncio.Queue)缓存所有收到的消息,消息处理器从队列中取消息处理,避免消息丢失,同时实现收发逻辑解耦

启动阶段批量数据同步

  • 使用asyncio.Semaphore控制并发请求数量,避免服务器过载
  • 批量创建请求并生成对应的Future,通过asyncio.gather等待所有请求完成;等待过程中仍可正常处理服务器推送的消息,不阻塞Bot的其他功能

简化代码示例

请求管理器核心实现

import asyncio
from typing import Dict, Optional

class RequestManager:
    def __init__(self):
        self._pending_requests: Dict[str, asyncio.Future] = {}
        self._lock = asyncio.Lock()

    async def track_request(self, request_key: str) -> asyncio.Future:
        async with self._lock:
            future = asyncio.Future()
            self._pending_requests[request_key] = future
            return future

    async def match_response(self, response_key: str, response_data):
        async with self._lock:
            future = self._pending_requests.pop(response_key, None)
            if future and not future.done():
                future.set_result(response_data)

消息处理器抽象与实现

from abc import ABC, abstractmethod

class MessageHandler(ABC):
    @abstractmethod
    async def handle(self, message: dict):
        pass

class RetrievedHandler(MessageHandler):
    def __init__(self, request_manager: RequestManager):
        self.request_manager = request_manager

    async def handle(self, message: dict):
        request_key = message.get("key")
        await self.request_manager.match_response(request_key, message)

class PrintJSONHandler(MessageHandler):
    async def handle(self, message: dict):
        # 示例:将消息转发到Discord
        print(f"处理PrintJSON消息: {message}")

内容的提问来源于stack exchange,提问作者T. P

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.01 16:17:32