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

如何让Telegram Bot中两个调用API的函数同时运行?

问题描述

我开发了一个Telegram机器人,处理聊天命令的代码如下:

def runBot():
    bot.polling(none_stop=True, interval=1, timeout=30, long_polling_timeout=65)

获取所有新消息(机器人已加入部分群组)的代码如下:

def getUpdates():
    ...
    MethodGetUpdates = f'https://api.telegram.org/bot{BOT_TOKEN}/getUpdates'
    offsetParam = {'offset': offset, 'allowed_updates': ['message']}
    response = requests.get(MethodGetUpdates, offsetParam)
    ...

(我会自行计算offset参数)

但这两部分只能单独运行,无法同时工作。我尝试用多线程解决,编写了如下代码:

def runBot():
    bot.polling(none_stop=True, interval=1, timeout=30, long_polling_timeout=65)

def runScheluders():
    schedule.every(70).seconds.do(getUpdates)

if __name__ == "__main__":
    t1 = threading.Thread(target=runBot)
    t2 = threading.Thread(target=runScheluders)
    t1.start()
    t2.start()

但该方案无效:机器人能正常响应命令,但getUpdates无法获取新消息,返回结果为:

{'ok': True, 'result': []}

单独运行任意一部分都能正常工作,请问如何让两者同时运行?


解决方案

问题核心是Telegram Bot的polling方法本身就是基于getUpdates实现的:当你启动bot.polling()后,它会自动持续调用getUpdates并更新offset值,导致你手动写的getUpdates因为offset落后,永远拿不到已经被polling进程处理过的新消息。

给你两种可行的解决思路:

思路1:统一用polling处理所有消息

直接在polling的消息处理逻辑里同时处理命令和其他消息,不需要额外开线程调用getUpdates。以python-telegram-bot库为例:

from telegram.ext import Updater, CommandHandler, MessageHandler, Filters

def handle_start_command(update, context):
    update.message.reply_text('收到/start命令!')

def handle_all_messages(update, context):
    # 这里处理所有非命令的消息,包括群组消息
    chat_info = f"[{update.message.chat.title or update.message.chat.id}]"
    print(f"{chat_info} 收到消息:{update.message.text}")

def runBot():
    updater = Updater(BOT_TOKEN, use_context=True)
    dp = updater.dispatcher
    # 注册命令处理器
    dp.add_handler(CommandHandler("start", handle_start_command))
    # 注册普通消息处理器(排除命令消息)
    dp.add_handler(MessageHandler(Filters.text & ~Filters.command, handle_all_messages))
    # 启动轮询
    updater.start_polling(none_stop=True, interval=1, timeout=30, long_polling_timeout=65)
    updater.idle()

if __name__ == "__main__":
    runBot()

思路2:完全自行实现轮询逻辑

如果一定要分开处理,就不要用库自带的polling,自己用线程实现完整的getUpdates轮询,同时处理命令和消息:

import requests
import time

BOT_TOKEN = "你的机器人Token"
offset = 0

def send_reply(chat_id, text):
    url = f"https://api.telegram.org/bot{BOT_TOKEN}/sendMessage"
    requests.post(url, data={'chat_id': chat_id, 'text': text})

def process_single_update(update):
    message = update.get('message', {})
    text = message.get('text', '')
    chat_id = message.get('chat', {}).get('id')
    
    if not chat_id:
        return
    
    # 处理命令
    if text.startswith('/'):
        command = text.split()[0]
        if command == '/start':
            send_reply(chat_id, "收到启动命令!")
    # 处理普通消息
    else:
        print(f"群组/私聊消息:{text}")

def getUpdates_loop():
    global offset
    while True:
        url = f'https://api.telegram.org/bot{BOT_TOKEN}/getUpdates'
        params = {
            'offset': offset,
            'allowed_updates': ['message'],
            'timeout': 60  # 长轮询超时
        }
        response = requests.get(url, params=params)
        result = response.json()
        
        if result['ok']:
            for update in result['result']:
                process_single_update(update)
                # 更新offset,确保下次只拿新消息
                if update['update_id'] >= offset:
                    offset = update['update_id'] + 1
        time.sleep(1)

if __name__ == "__main__":
    getUpdates_loop()

补充:你的原方案为什么无效?

  1. bot.polling()会自动推进offset,导致你手动调用的getUpdates永远拿不到新消息;
  2. 你的runScheluders函数只定义了任务,但没有启动schedule的循环——需要加上while True: schedule.run_pending(); time.sleep(1)才会执行定时任务,但就算加上,也会因为offset被polling占用而无法获取消息。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 01:07:38