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

如何修改Telegram Bot代码实现多用户并行访问并有序存储用户答案

核心问题根源
  • 你同时运行了多个GetUpdates死循环,Telegram Bot API的offset是全局唯一的,多个循环争抢offset会直接导致消息丢失、处理阻塞
  • 在BotOnMessage的switch分支里直接await AnonymEN(),等于主消息循环被挂起,必须等AnonymEN完全执行完才会处理下一条消息,自然会出现多用户阻塞的情况
  • AnonymEN执行完后递归调用BotOnMessage,会导致循环嵌套层数越来越高,存在极高的内存泄漏风险
修复方案

1. 统一全局消息入口,移除嵌套的拉取消息逻辑

整个Bot只保留一个全局的GetUpdates死循环,所有用户消息都在这一个循环里处理,不要在AnonymEN、AnonymGR这类业务方法里再单独开拉取消息的逻辑。

2. 新增用户会话状态标记

你现在的ConcurrentDictionary仅存储了用户答案,补充用户当前的会话阶段字段,实现每个用户的问答流程独立跟踪:

// 定义用户会话状态枚举
enum UserState
{
    Idle, // 初始空闲状态
    ChoosingLanguage,
    ChoosingENOption,
    EnteringENName,
    EnteringENAge
    // 德语对应流程的状态可自行补充
}
// 调整存储结构,同时存会话状态和用户答案
class UserSession
{
    public UserState CurrentState { get; set; }
    public string[] Answers { get; set; }
}
static readonly ConcurrentDictionary<int, UserSession> UserSessions = new ConcurrentDictionary<int, UserSession>();

3. 重构消息处理逻辑,按用户状态分流

所有消息处理逻辑都放到唯一的主循环中,拿到消息后先查询对应用户的会话状态,再走对应业务分支:

async static Task BotOnMessage()
{
    int offset = 0;
    int timeout = 10; // 建议设为10-30,减少空轮询频率
    await bot.SetWebhookAsync("");
    while (true)
    {
        var updates = await bot.GetUpdatesAsync(offset, timeout);
        foreach (var update in updates)
        {
            var message = update.Message;
            if (message?.Type != MessageType.Text) 
            {
                offset = update.Id + 1;
                continue;
            }
            int userId = (int)message.From.Id;
            // 无会话则自动初始化
            var session = UserSessions.GetOrAdd(userId, _ => new UserSession 
            { 
                CurrentState = UserState.Idle, 
                Answers = Array.Empty<string>() 
            });

            switch(session.CurrentState)
            {
                case UserState.Idle:
                    HandleIdleState(message, session);
                    break;
                case UserState.ChoosingENOption:
                    HandleENOptionState(message, session);
                    break;
                case UserState.EnteringENName:
                    HandleENNameState(message, session);
                    break;
                case UserState.EnteringENAge:
                    HandleENAgeState(message, session);
                    break;
                // 其他状态对应的处理方法自行补充
            }
            offset = update.Id + 1;
        }
    }
}

4. 拆分业务逻辑,移除阻塞调用

把原来AnonymEN里的逻辑拆成对应状态的处理方法,比如输入姓名、输入年龄的逻辑分别放到对应的状态处理方法中,不要await任何会阻塞主循环的方法,所有业务处理都是单次消息响应,执行完直接回到主循环处理下一条消息。

5. 会话结束后直接重置状态

用户完成所有问答提交后,直接删除对应用户的会话或者把状态改回Idle即可,不需要递归调用BotOnMessage,主循环会自动处理后续的用户消息。

额外优化点
  • 不要共用全局的createdDateNoTime变量,每个用户的提交时间取当前实时时间即可,避免多用户并发时时间错乱
  • 给会话增加过期时间,定期清理超过24小时无操作的会话,避免内存占用持续升高

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 14:57:03