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

部署Heroku后Python Telegram Bot的ConversationHandler工作异常

问题根因

这个问题的核心是ConversationHandler默认将会话状态存储在当前进程的内存中,部署到Heroku后触发了进程内存不共享的问题:

  • 本地测试时是单进程运行,会话状态始终存在当前进程内存中,所以流程正常
  • Heroku上部署WSGI应用(如Flask+Gunicorn)默认会启动多个worker进程,每个进程的Dispatcher实例独立,内存数据不互通。用户前序请求落到A进程,状态存在A的内存中,后续请求落到B进程时,B进程没有对应会话数据,就会出现日志中的state None无响应情况。双击按钮成功是刚好这次请求落到了持有会话状态的进程中。

另外还有次要触发原因:Telegram服务器如果10秒内没有收到webhook请求的响应,会重试推送同一条更新,也会导致同一条更新被多次处理,出现多条重复日志。

解决方法

临时验证方案(快速确认问题)

修改Heroku的Procfile启动命令,将Gunicorn的worker数改为1,强制所有请求都落到同一个进程,会话状态可以正常读取:

web: gunicorn --workers=1 你的启动文件名:app

这个方案的缺点是单进程性能有限,且Heroku进程重启后所有会话状态都会丢失,仅适合验证问题。

永久解决方案

1. 配置会话持久化

使用Python Telegram Bot内置的持久化机制,将会话状态存储到所有进程都能访问的外部存储,避免内存不共享问题:

  • 如果你能接入Redis,可以直接使用RedisPersistence
  • 如果你已使用数据库存储业务数据,可以自己实现基于数据库的Persistence子类
  • 临时测试也可以用PicklePersistence,但注意Heroku临时文件系统重启会丢失数据

示例配置(以v13.x版本为例):

from telegram.ext import PicklePersistence, Dispatcher

def setup(bot, db_pool):
    # 初始化持久化实例
    persistence = PicklePersistence(filename='conv_states')
    # 创建dispatcher时传入持久化参数
    dispatcher = Dispatcher(bot, None, workers=0, persistence=persistence)
    # 后续注册handler逻辑不变
    ...

2. 增加更新去重逻辑

在webhook入口处增加update_id去重,避免Telegram重试的重复更新被多次处理:

# 可以用redis或者数据库存储已处理的update_id
processed_updates = set()

@app.route(f"/{TOKEN}", methods=["POST"])
def respond():
    update_json = request.get_json(force=True)
    update_id = update_json.get('update_id')
    if update_id in processed_updates:
        return "ok"
    processed_updates.add(update_id)
    update = telegram.Update.de_json(update_json, bot)
    dispatcher.process_update(update)
    return "ok"

3. 优化回调处理速度

确保所有回调处理逻辑在10秒内完成返回,避免Telegram触发重试,耗时操作可以放到后台异步处理。

内容的提问来源于stack exchange,提问作者Palash Singh Raghuwanshi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 18:36:04