为什么我的Discord机器人on_ready函数无限循环且无法写入PostgreSQL数据
原因分析
on_ready无限循环的根因
DiscordComponents(bot)初始化放在on_ready内部,该组件初始化会修改bot实例的内部状态、触发网关重连,而on_ready本身会在bot每次重连成功后自动调用,形成循环触发逻辑- 空
except语句捕获了所有异常,包括协程中断、数据库连接断开等错误,没有错误抛出,bot不会崩溃退出,会持续重复执行on_ready - 全局共享的数据库连接/游标在大量循环插入时容易出现阻塞、断开,触发bot内部重连逻辑,进一步加剧循环问题
数据库无法写入的根因
- 表结构定义错误:
id字段设置为BIGSERIAL类型,这是PostgreSQL的自增主键类型,不需要主动传入值。你主动插入Discord用户ID作为主键值,会触发主键冲突,同时自增序列不会同步更新,后续插入全部失败。 - SQL构造错误:直接用字符串拼接构造SQL语句,当
member对象转字符串后包含单引号时,会触发SQL语法错误,所有错误都被空except吞掉,插入直接跳过。 - 网关权限缺失:discord.py v1.5及以上版本需要在开发者后台开启成员网关意图,同时代码中显式声明
intents.members = True,否则guild.members只能获取到bot自身,没有其他成员数据可以插入。
修复方案
调整组件初始化位置
把DiscordComponents(bot)移到on_ready外部,放在bot实例化之后的全局位置,避免重复初始化触发重连。增加on_ready执行标记
避免事件被重复触发:
is_ready = False @bot.event async def on_ready(): global is_ready if is_ready: return is_ready = True # 原有逻辑
- 修正表结构和SQL操作
- 把主键字段类型改为
BIGINT,适配Discord用户ID:
CREATE TABLE IF NOT EXISTS users ( name VARCHAR(255), id BIGINT PRIMARY KEY, xp INT );
- 使用参数化查询代替字符串拼接,避免语法错误和注入风险,同时明确捕获主键重复异常:
from psycopg2 import IntegrityError # 插入逻辑替换为 try: cursor.execute( "INSERT INTO users (name, id, xp) VALUES (%s, %s, %s)", (str(member), member.id, 0) ) except IntegrityError: # 用户已存在,直接跳过 continue
- 开启成员意图
实例化bot时显式声明成员意图:
import discord from discord.ext import commands intents = discord.Intents.default() intents.members = True bot = commands.Bot(command_prefix="你的前缀", intents=intents)
同时需要到Discord开发者后台的Bot设置页,开启Server Members Intent开关。
内容的提问来源于stack exchange,提问作者Hallteon
相关产品推荐
相关产品推荐

