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

如何避免Socket新连接时同一ID重复触发setInterval调用API?

解决方案

核心思路是维护一个全局的匹配状态管理对象,记录每个match_id对应的定时器和订阅该匹配的Socket连接,以此避免重复发起API请求,同时统一推送数据给所有订阅用户。

修改后的完整代码

// 全局对象:存储活跃匹配的定时器和订阅Socket集合
const activeMatches = {};

socket.on('fancy', async (data) => {
  const { match_id } = data;
  
  // 检查该匹配是否已有运行中的定时任务
  if (activeMatches[match_id]) {
    // 将当前Socket加入订阅列表
    activeMatches[match_id].sockets.add(socket);
    // 可选:立即推送一次当前API数据给新订阅用户,不用等下一秒
    try {
      const fancy = await callapi(match_id);
      socket.emit(`fancy_${match_id}`, fancy);
    } catch (err) {
      console.error(`获取匹配${match_id}数据失败:`, err);
    }
    return;
  }

  // 初始化该匹配的订阅Socket集合(用Set避免重复添加同一Socket)
  const sockets = new Set();
  sockets.add(socket);

  // 创建定时任务,每秒调用API并推送给所有订阅用户
  const intervalId = setInterval(async () => {
    try {
      const fancy = await callapi(match_id);
      // 遍历所有订阅Socket推送数据
      sockets.forEach(sock => {
        sock.emit(`fancy_${match_id}`, fancy);
      });
    } catch (err) {
      console.error(`定时获取匹配${match_id}数据失败:`, err);
      // 可选:如果API持续失败,可考虑停止定时任务并清理状态
      // clearInterval(intervalId);
      // delete activeMatches[match_id];
    }
  }, 1000);

  // 将该匹配的状态存入全局对象
  activeMatches[match_id] = { intervalId, sockets };

  // 监听Socket断开事件,清理订阅关系
  socket.on('disconnect', () => {
    sockets.delete(socket);
    // 如果该匹配没有订阅用户了,停止定时任务并释放资源
    if (sockets.size === 0) {
      clearInterval(intervalId);
      delete activeMatches[match_id];
      console.log(`匹配${match_id}已无订阅用户,停止定时任务`);
    }
  });
});

// API调用函数(优化变量声明和错误处理)
const callapi = (id) => {
  return new Promise((resolve, reject) => {
    const options = {
      method: 'POST',
      url: 'url',
      formData: { id }
    };
    request(options, function (error, response) {
      if (error) {
        console.error(`API请求失败(ID: ${id}):`, error);
        return reject(error);
      }
      try {
        const data = JSON.parse(response.body).data;
        resolve({ status: 'success', data });
      } catch (parseErr) {
        console.error(`API响应解析失败(ID: ${id}):`, parseErr);
        reject(parseErr);
      }
    });
  });
};

关键改进说明

  • 避免重复任务:通过activeMatches全局对象跟踪每个match_id的运行状态,同一匹配只会启动一个定时任务。
  • 统一数据推送:每个匹配的API响应会推送给所有订阅用户,不用为每个用户单独调用API,减少服务器压力。
  • 自动资源清理:用户断开连接时自动从订阅列表移除;当某匹配没有订阅用户时,立即停止定时任务并清理内存,防止无效资源占用。
  • 优化错误处理:给API调用和响应解析环节添加错误日志,便于排查问题,也可根据业务需求添加重试逻辑。
  • 提升用户体验:新用户订阅时立即推送一次当前数据,不用等待下一秒的定时任务。

内容的提问来源于stack exchange,提问作者Piyush

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 06:23:11