C#开发Telegram Bot遇单用户阻塞,其他用户无法使用求排查
问题排查与解决方案
问题根源
- 阻塞线程池的无限循环:在
HandleUpdateAsync方法内部,你写了while (true)的无限循环,并且用.Result同步调用GetUpdatesAsync,直接阻塞了当前处理请求的线程池线程。Telegram.Bot的StartReceiving依赖线程池处理并发更新,一旦线程被这个循环占死,其他用户的消息就无法得到处理。 - 重复轮询更新:
StartReceiving已经完成了更新轮询和分发工作,手动调用GetUpdatesAsync属于重复操作,不仅无意义,还会导致更新处理逻辑混乱、占用资源。 - 未正确处理CallbackQuery:当前
HandleUpdateAsync只处理Message类型的更新,但内联键盘点击会触发CallbackQuery类型的更新,你需要直接在HandleUpdateAsync中处理这类更新,而非手动轮询获取。
修改后的代码
Business类的MainMethod和HandleUpdateAsync调整
public async Task MainMethod() { var botClient = new TelegramBotClient("token"); using CancellationTokenSource cts = new(); ReceiverOptions receiverOptions = new() { // 明确允许需要处理的更新类型,包含消息和回调查询 AllowedUpdates = new[] { UpdateType.Message, UpdateType.CallbackQuery } }; botClient.StartReceiving( updateHandler: HandleUpdateAsync, pollingErrorHandler: HandlePollingErrorAsync, receiverOptions: receiverOptions, cancellationToken: cts.Token ); var me = await botClient.GetMeAsync(); Console.WriteLine($"Start listening for @{me.Username}"); Console.ReadLine(); cts.Cancel(); } async Task HandleUpdateAsync(ITelegramBotClient botClient, Update update, CancellationToken cancellationToken) { // 处理普通消息(如/start命令) if (update.Message is { } message && message.Text is { } messageText) { var chatId = message.Chat.Id; Console.WriteLine($"Received a '{messageText}' message in chat {chatId}."); switch (messageText) { case "/start": await StartMessage(botClient, chatId, cancellationToken); break; default: break; } } // 处理内联键盘的回调查询 else if (update.CallbackQuery is { } callbackQuery) { var chatId = callbackQuery.Message.Chat.Id; var callbackData = callbackQuery.Data; Console.WriteLine($"Received callback query '{callbackData}' from chat {chatId}."); // 先回复回调,避免用户看到持续加载状态 await botClient.AnswerCallbackQueryAsync( callbackQueryId: callbackQuery.Id, cancellationToken: cancellationToken ); switch (callbackData) { case "/start": await StartMessage(botClient, chatId, cancellationToken); break; case "BuyService": await BuyService(botClient, update, chatId, cancellationToken); break; // 其他回调逻辑 } } }
关键修改点说明
- 移除手动轮询代码:删掉
HandleUpdateAsync里的无限循环和GetUpdatesAsync调用,让StartReceiving统一处理所有更新分发。 - 允许CallbackQuery更新:在
ReceiverOptions中明确指定需要处理的更新类型,确保回调查询能被推送到处理方法。 - 拆分消息处理逻辑:分别处理
Message和CallbackQuery类型的更新,逻辑更清晰,不会阻塞线程。 - 添加回调反馈:处理CallbackQuery时先调用
AnswerCallbackQueryAsync,给用户的键盘点击操作提供反馈,避免无响应状态。
内容的提问来源于stack exchange,提问作者Hossein.Goodarzi
相关产品推荐
相关产品推荐

