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

Telegram JS机器人重复发送消息问题排查求助

问题分析与解决方案

核心问题

  1. setInterval 未考虑异步任务耗时:7秒触发一次watchChanges,但如果watchChanges内的异步操作(数据库查询、消息发送)执行时间超过7秒,setInterval会无视前一次任务是否完成,直接触发下一次,导致多轮任务同时处理群组,重复发送消息。
  2. forEach 遍历异步函数的错误用法:groups.forEach(async (group) => {}) 中,forEach不会等待异步函数执行完成,会一次性启动所有checkGroup任务,但如果前一轮setInterval的任务还没结束,新的一轮又开始,就会重复处理同一个群组。
  3. 无任务锁机制:没有标记正在处理的群组或全局任务状态,无法阻止重复触发的任务继续执行。
  4. 回调时机错误:getTransaction中的callback('Looped Successfully')在forEach之后立即调用,没有等待所有checkGroup完成,导致watchChanges提前结束,进一步加剧setInterval的重复触发问题。

修复步骤

1. 替换setInterval为带防抖的定时任务

用setTimeout替代setInterval,确保前一次任务完全执行后再启动下一次:

// index.js
const Robot = require("bot");
const bot = new Telegraf(TGAPIKey);
const instance = new Robot(bot);

async function runLoop() {
  try {
    await instance.watchChanges();
  } catch (error) {
    console.log(error);
  } finally {
    // 前一次任务完成后,再等待7秒启动下一次
    setTimeout(runLoop, 7000);
  }
}

// 启动循环
runLoop();

2. 正确处理异步遍历

将forEach改为for...of,确保每个checkGroup完成后再处理下一个群组:

// crypt.js
class transaction{
  async getTransaction(callback) {
    let groups = await Group.find();
    
    // 用for...of替代forEach,保证异步顺序执行
    for (const group of groups) {
      try {
        await checkGroup(group);
        console.log('Checked Group', group?.groupName);
      } catch (err) {
        console.log('Failed to check group', err);
      }
    }
    // 所有群组处理完成后再调用回调
    callback('Looped Successfully');
  }
}

3. 添加全局任务锁

在Bot类中添加一个标记,防止任务重复执行:

// bot.js
const { transaction } = require("./crypt");

class Bot {
  constructor(bot) {
    this.bot = bot;
    this.transaction = new transaction();
    this.isProcessing = false; // 任务锁标记
  }
  
  completeLoop(message) {
    console.log("successfull loop", message);
  }
  
  async watchChanges() {
    // 如果正在处理,直接返回
    if (this.isProcessing) return;
    this.isProcessing = true;
    
    try{
      await Promise.all([
        this.transaction.getTransaction(this.completeLoop.bind(this)),
      ]);
    } catch (error) {
      console.log(error);
    } finally {
      // 任务完成后释放锁
      this.isProcessing = false;
    }
  }
}
 
module.exports = Bot;

4. 修复sendMessage的上下文问题

确保sendMessage能正确获取bot实例:

// crypt.js
// 修改checkGroup,传入bot实例
async function checkGroup(group, bot) {
  // <--- Check Stuff---&gt;
  if(checkStuff) {
    await sendMessage(msg, bot);
  } else {
    return;
  }
}

async function sendMessage(msg, bot) {
  await bot.telegram.sendMessage(msg).catch((error) => {
    console.log('error snd msg', error);
  });
}

// 在bot.js的watchChanges中调用时传入this.bot
// this.transaction.getTransaction(this.completeLoop.bind(this), this.bot);
// 然后crypt.js的getTransaction接收bot参数,传递给checkGroup

额外建议

  • 给每个群组添加处理标记,比如在数据库中记录lastProcessedTime,避免短时间内重复处理同一群组。
  • 增加日志的详细程度,记录每次处理的群组ID、时间戳,方便排查重复触发的具体场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 03:11:51