python-telegram-bot内联按钮长时间延迟后无响应问题求助
长期交互式Telegram内联按钮失效问题排查与解决方案咨询
问题背景
我正在开发一个基于PySide6构建GUI的Python应用,通过python-telegram-bot v13.7与用户交互。应用的自动化工作流可能耗时数小时,因此搭建了Telegram状态消息系统:当流程阻塞或需要用户修改输入时,会通过内联键盘提供「修改输入」或「停止流程」的选项,要求这些按钮在用户8小时以上未交互后仍能正常响应。
当前症状
机器人发送的内联按钮数小时后无响应,具体表现为:
- 用户点击"旧"按钮时,Telegram显示无限加载动画但无反应
- 机器人的
CallbackQueryHandler未触发(无回调日志) - 多数情况下
python-telegram-bot的错误处理器未记录明确错误
已尝试的解决方案
为解决回调查询超时问题,实现了消息刷新机制:
- 追踪带按钮的消息
- 定时器每约45分钟运行一次
- 若消息超过阈值,执行:
- 用
bot.delete_message()删除旧消息 - 用
bot.send_message()发送含相同内容和新内联按钮的消息 - 追踪新消息ID
- 用
该机制在1小时、2小时、7小时测试中有效,但长期运行仍频繁失效,尤其是在蜂窝网络环境、PC短暂休眠(虽已配置不休眠)场景下。
运行环境
- Python 3.11.6
- python-telegram-bot v13.7
- Windows 10 Pro
- 采用轮询模式(
updater.start_polling())
咨询问题
- PTB v13.7中处理长期交互式按钮的更可靠方式?
- 是否忽略了回调查询生命周期或轮询持久性的核心知识点?
- 网络中断或短暂休眠是否会导致轮询无法自动恢复,进而错过回调?
- 除切换为文本回复或ConversationHandler外,确保按钮长期有效的最佳实践?
最小复现脚本
import os import time import logging import threading from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup, Bot # Assumes pip install python-telegram-bot==13.7 (or your specific v13 version) from telegram.ext import Updater, CommandHandler, CallbackQueryHandler, CallbackContext, MessageHandler, Filters from dotenv import load_dotenv # Optional: pip install python-dotenv # --- Configuration --- load_dotenv() # Load .env file if it exists BOT_TOKEN = os.getenv("TELEGRAM_BOT_TOKEN", "YOUR_BOT_TOKEN") # <<< REPLACE or use .env file TARGET_CHAT_ID = 123456789 # <<< REPLACE with your Telegram Chat ID (integer) # --- Logging --- logging.basicConfig( format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO ) logger = logging.getLogger(__name__) # --- State --- last_callback_data = None callback_received_event = threading.Event() # Used to signal if callback arrives during wait # --- Handlers --- def start(update: Update, context: CallbackContext) -> None: logger.info(f"Received /start from user {update.effective_user.id}") update.message.reply_text(f"Bot started. Use /sendmre to send the test message to chat ID {TARGET_CHAT_ID}.") def send_mre_message_command(update: Update, context: CallbackContext) -> None: logger.info(f"Received /sendmre from user {update.effective_user.id}") if send_initial_mre_message(context.bot): update.message.reply_text("MRE test message sent.") else: update.message.reply_text("Failed to send MRE test message. Check logs and config.") def send_initial_mre_message(bot_instance: Bot) -> bool: """Sends the message with buttons for the long wait test.""" if not isinstance(TARGET_CHAT_ID, int) or TARGET_CHAT_ID == 123456789: logger.error("TARGET_CHAT_ID is not set correctly (must be an integer).") return False keyboard = [ [InlineKeyboardButton("Option 1 (Long Wait)", callback_data='opt_1_long')], [InlineKeyboardButton("Option 2 (Long Wait)", callback_data='opt_2_long')], [InlineKeyboardButton("Cancel (Long Wait)", callback_data='cancel_long')], ] reply_markup = InlineKeyboardMarkup(keyboard) try: logger.info(f"Sending MRE message to chat ID {TARGET_CHAT_ID}...") bot_instance.send_message( chat_id=TARGET_CHAT_ID, text='MRE Started: Try clicking a button on this message after 8+ hours:', reply_markup=reply_markup ) logger.info(f"MRE message sent successfully to {TARGET_CHAT_ID}.") return True except Exception as e: logger.error(f"Failed to send MRE message to {TARGET_CHAT_ID}: {e}") return False def button_callback(update: Update, context: CallbackContext) -> None: """Handles button clicks.""" global last_callback_data query = update.callback_query logger.info(f"--- Button Callback Received (Data: {query.data}) ---") try: query.answer() except Exception as e: logger.warning(f"Could not answer callback query: {e}") last_callback_data = query.data logger.info(f"Stored callback data: {last_callback_data}") try: query.edit_message_text(text=f"✅ Selection received: {query.data}\n(Processed: {time.strftime('%H:%M:%S')})") except Exception as e: logger.warning(f"Could not edit message: {e}") callback_received_event.set() logger.info(f"--- Button Callback Finished ---") def text_handler(update: Update, context: CallbackContext) -> None: logger.info(f"Ignoring text message from {update.effective_user.id}") def error_handler(update: object, context: CallbackContext) -> None: logger.error(f'Update "{update}" caused error "{context.error}"', exc_info=context.error) # --- Main --- def main() -> None: if not BOT_TOKEN or BOT_TOKEN == "YOUR_BOT_TOKEN": print("ERROR: Telegram Bot Token not found.") print("Set the BOT_TOKEN variable or use a .env file.") return if not isinstance(TARGET_CHAT_ID, int) or TARGET_CHAT_ID == 123456789: print("ERROR: Please replace TARGET_CHAT_ID with your integer chat ID.") return # Ensure use_context=True for PTB v13.x updater = Updater(BOT_TOKEN, use_context=True) dispatcher = updater.dispatcher dispatcher.add_handler(CommandHandler("start", start)) dispatcher.add_handler(CommandHandler("sendmre", send_mre_message_command)) dispatcher.add_handler(CallbackQueryHandler(button_callback)) dispatcher.add_handler(MessageHandler(Filters.text & ~Filters.command, text_handler)) dispatcher.add_handler(error_handler) logger.info("Starting bot polling...") updater.start_polling() logger.info("Bot polling started.") print("Bot started. Send /start to the bot, then /sendmre.") print(f"(Test message will be sent to Chat ID: {TARGET_CHAT_ID})") print(f"Wait 8+ hours after the message appears, then click a button.") print("Check console logs for callback details. Press Ctrl+C to stop.") updater.idle() logger.info("Bot stopping.") if __name__ == '__main__': main()
内容的提问来源于stack exchange,提问作者Kingston
相关产品推荐
相关产品推荐

