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

Docker环境多Telegram Bot启动报错,求线程/异步运行解决方案

Docker中运行多Telegram Bot报错及线程模式运行解决方案

问题描述

本地Windows/Mac环境可正常启动大量Telegram Bot,但Docker容器中运行时触发以下报错:

backend1-1 | File "uvloop/loop.pyx", line 2887, in uvloop.loop.Loop.add_signal_handler
backend1-1 | ValueError: add_signal_handler() can only be called from the main thread

核心相关代码:

class BaseTelegramBot:
    """Telegram Bot基类"""

    def __init__(self, bot_data):
        super().__init__()
        self.bot = Bot(token=self.token)
        self.dispatcher = Dispatcher()

bot = BaseTelegramBot(bot_data=bot_data)
asyncio.run(bot.start())  

async def start(self):
        py_logger.info(f"Bot {self.bot_data.id} 已启动")
        await self.bot.set_my_commands(commands=self.commands)
        await self.dispatcher.start_polling(self.bot)

报错原因

Docker环境下,Python asyncio默认使用uvloop作为事件循环(Linux环境自动启用),而start_polling内部会尝试添加信号处理器,uvloop严格要求该操作必须在主线程执行。本地环境可能使用默认的SelectorEventLoop,对线程限制宽松;或者本地代码在主线程执行,而Docker中因启动逻辑导致代码运行在非主线程,从而触发报错。

解决方案

方案1:线程模式批量启动Bot

通过线程池为每个Bot创建独立的事件循环,确保每个Bot的信号处理器操作在所属线程的主线程执行:

import asyncio
from concurrent.futures import ThreadPoolExecutor

class BaseTelegramBot:
    """Telegram Bot基类"""
    def __init__(self, bot_data):
        super().__init__()
        self.bot = Bot(token=self.token)
        self.dispatcher = Dispatcher()
        self.bot_data = bot_data

    async def start(self):
        py_logger.info(f"Bot {self.bot_data.id} 已启动")
        await self.bot.set_my_commands(commands=self.commands)
        # 启动轮询,可根据库文档调整参数避免自动添加信号处理器
        await self.dispatcher.start_polling(self.bot, skip_updates=True)

def run_bot_thread(bot_data):
    # 为当前线程创建并设置独立事件循环
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    bot = BaseTelegramBot(bot_data=bot_data)
    try:
        loop.run_until_complete(bot.start())
    finally:
        loop.close()

# 批量启动逻辑
if __name__ == "__main__":
    bot_configs = [...]  # 替换为你的所有Bot配置列表
    # 根据机器性能设置最大线程数
    with ThreadPoolExecutor(max_workers=5) as executor:
        executor.map(run_bot_thread, bot_configs)

方案2:强制使用默认事件循环

如果不想修改线程逻辑,可强制禁用uvloop,使用Python默认的SelectorEventLoop规避线程限制:

import asyncio
import sys

# 在代码启动前设置事件循环策略
if sys.platform != 'win32':
    asyncio.set_event_loop_policy(asyncio.DefaultEventLoopPolicy())

# 原启动代码
bot = BaseTelegramBot(bot_data=bot_data)
asyncio.run(bot.start())

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 01:10:17