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

Node.js+Telegraf+MySQL开发Telegram Bot多请求异常求助

问题根因

你现在遇到的并发串数据、进程崩溃报错、运行久了数据丢失,全是代码写法问题,不需要额外复杂框架就能解决,核心问题有4个:

  • 把单用户请求产生的dataStore存在全局作用域,所有并发用户的请求共用同一个数组,A用户刚查完的数据,会被B用户的请求直接覆盖,必然出现不同用户数据混淆的问题
  • 变量作用域混乱,dataStore没有在使用它的代码块内声明,异步请求时序一乱,就会触发ReferenceError: dataStore is not defined;你在数据库回调里直接throw err会直接崩掉整个Node进程,机器人自然就冻结无响应
  • 用mysql.createConnection创建单连接处理请求,本身不支持并发,连接意外断开后也不会自动重连,跑久了连接失效就会出现数据丢失、请求无响应的问题;另外你贴的连接代码本身还有语法错误,配置对象没有闭合,漏了}),连接从一开始就不稳定
  • 数据库查询结果的判断逻辑写错了,conn.query返回的查询结果是数组,就算没匹配到数据也是空数组,直接写if(result==0)判断逻辑不可靠,很容易走到错误分支
修复方案

按下面步骤改就能解决所有问题:

  1. 把单数据库连接换成连接池,自动管理连接生命周期、支持并发请求,建议直接用mysql2包替代老的mysql包,支持Promise写法,异步逻辑更不容易出错
const mysql = require('mysql2/promise');
// 创建连接池替代单连接
const pool = mysql.createPool({
  host: "你的数据库地址",
  user: "数据库用户名",
  password: "数据库密码",
  database: "DB",
  waitForConnections: true,
  connectionLimit: 10, // 按你的并发量调整,一般小机器人10个连接足够
  queueLimit: 0
});
  1. 注册Telegraf自带的session中间件,把每个用户的临时状态存在自己的会话上下文里,彻底隔离不同用户的数据,绝对不要再用全局变量存单用户的请求数据
const { Telegraf, Scenes, session } = require('telegraf');
const bot = new Telegraf('你的机器人Token');
// 一定要在注册场景之前挂载session中间件
bot.use(session());
// 注册你自己的wizard场景
const stage = new Scenes.Stage([/* 把你写的scanstarterpack等场景放到这里 */]);
bot.use(stage.middleware());
  1. 改写查询逻辑,把查询到的用户数据存在当前请求的ctx.session里,不要碰全局变量
// 删掉所有全局声明的dataStore变量,完全不要用
const arr = [wizardData.number, wizardData.firstnumber]
const sql = 'SELECT DB.tblbotusers.Name,DB.tblbotusers.PhoneNumber AS phoneNumber,DB.tblbotusers.IDDealer ,DB.tblbotusers.UserID FROM DB.tblbotusers WHERE DB.tblbotusers.PhoneNumber IN (?);'
// 用连接池执行查询
const [result] = await pool.query(sql, [arr]);
// 正确判断空结果
if(result.length === 0) {
  console.log("Number Not Found In Database")
  ctx.replyWithHTML("❌Your <b>number</b> is not found in the database! Please register",
    Markup.inlineKeyboard([
      [Markup.button.callback('Return to main menu','mainmenu')]
    ])
  )
  return;
}
console.log(result)
// 数据存在当前用户的会话里,和其他用户完全隔离
ctx.session.dataStore = [];
result.forEach(item => {
  ctx.session.dataStore.push({
    Name:item.Name,
    phoneNumber:item.phoneNumber,
    IDDealer:item.IDDealer,
    UserID:item.UserID
  })
});
  1. 改写后续插入逻辑,从当前用户会话里取数据,不要访问全局变量,同时改掉全局抛错的写法
console.log(newagentFN+" "+newagentMSISDN+" "+newagentMSISDNtxt)
// 从当前用户会话取数据,不会串到其他用户,也不会出现未定义
ctx.session.dataStore.forEach(item =>{
  const newagent = [wizardData.agentaddname[0],wizardData.agentaddname[1],wizardData.agentidpassnum,status,wizardData.agentnumber,item.IDDealer];
  const sql='INSERT INTO DB.tblbotagentstoadd(FirstName,LastName,IDNumber,SpecialInstructions,MSISDN,IDDealer) VALUES (?);';
  pool.query(sql,[newagent],function(err,result){
    if (err){
      // 不要throw err,不然会直接崩掉整个进程,打日志返回错误即可
      console.error('插入数据失败:', err);
      ctx.reply('操作失败,请稍后重试');
      return;
    }
  });
});
// 用完临时数据记得清理,避免内存占用
ctx.session.dataStore = [];

注意:默认的内存session只适合本地调试用,生产环境建议把session存储到MySQL或者Redis里,不然机器人重启之后所有用户的会话状态都会清空,并发高了内存占用也会持续上涨。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 22:24:18