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

Python异步WebSocket Bot的RuntimeError与RuntimeWarnings处理问题

问题分析与修复方案

错误根源拆解

  1. 后台任务未被跟踪/取消:你用asyncio.create_task创建的WebSocket监听任务没有保存引用,Bot关闭时无法终止这个无限循环的任务,导致事件循环一直处于运行状态,触发RuntimeError: Cannot close a running event loop。
  2. Polling调用与事件循环冲突:application.run_polling()内部会接管事件循环的生命周期管理,退出时可能未正确释放资源,导致后续的shutdown调用在仍运行的循环中执行。
  3. 潜在的协程调度问题:如果main函数未通过标准方式启动(比如asyncio.run),或异常场景下initialize/shutdown的await逻辑被跳过,就会出现协程未等待的警告。

修复后的完整代码

import asyncio
from telegram import Bot
from telegram.ext import Application
import websockets

async def send_notification_to_chat(bot, message, chat_id):
    try:
        await bot.send_message(chat_id=chat_id, text=message)
        print("Message sent successfully.")
    except Exception as e:
        print(f"Failed to send message: {str(e)}")

async def logs_Tokens(callback, bot, chat_id):
    uri = "wss://your-websocket-uri"
    while True:
        try:
            async with websockets.connect(uri) as websocket:
                print("Connected to WebSocket server")
                while True:
                    message = await websocket.recv()
                    # 此处添加你的消息处理逻辑
                    await callback(bot, "Token activity detected!", chat_id)
        except websockets.exceptions.ConnectionClosed:
            print("WebSocket connection closed, reconnecting...")
            await asyncio.sleep(5)  # 重连前等待避免频繁重试
        except Exception as e:
            print(f"WebSocket error: {str(e)}")
            await asyncio.sleep(5)

async def main():
    bot = Bot(token="your-token-here")
    application = Application.builder().bot(bot).build()
    chat_id = "chat_number"
    
    # 保存后台任务引用,方便后续取消
    ws_task = asyncio.create_task(logs_Tokens(send_notification_to_chat, bot, chat_id))

    try:
        await application.initialize()
        # 改用start_polling + wait_stop,替代run_polling,更灵活控制循环生命周期
        await application.start_polling()
        await application.updater.wait_stop()
    finally:
        # 主动取消WebSocket后台任务
        ws_task.cancel()
        try:
            await ws_task
        except asyncio.CancelledError:
            print("WebSocket task cancelled successfully")
        # 确保应用资源正常释放
        await application.shutdown()

if __name__ == "__main__":
    # 用标准方式启动异步主函数
    asyncio.run(main())

关键修改说明

  • 移除多余lambda包装:send_notification_to_chat本身是异步函数,直接传入即可,无需额外lambda包装。
  • 跟踪并取消后台任务:保存ws_task引用,在finally块中主动取消并等待任务结束,确保事件循环能正常退出。
  • 调整Polling调用逻辑:用start_polling + wait_stop替代run_polling,避免内部循环管理冲突,更清晰控制Bot的启动与停止。
  • 添加WebSocket异常处理:处理连接关闭等异常,避免任务意外崩溃,同时添加重连等待逻辑,提升稳定性。

效果验证

修改后:

  • 后台WebSocket任务会在Bot关闭时被正确终止,事件循环可正常退出,解决Cannot close a running event loop错误。
  • initialize和shutdown协程都会被正确await,消除未等待的警告。
  • Bot可正常初始化、处理WebSocket消息,并在收到停止信号时优雅关闭。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 15:33:33