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

Discord机器人连接MongoDB保存数据报DNS超时错误

问题背景

开发Discord服务器需支持人员审批的角色分配系统,核心逻辑需要持久化存储待审批申请对应的消息ID、申请发起用户ID,目前非数据库相关业务逻辑运行正常,数据库相关代码启动即报错。

相关代码

业务事件代码

cluster = MongoClient('mongodb+srv://corry:pa4-pD6-3Dj-AdT@cluster0.gi8x6.mongodb.net/?retryWrites=true&w=majority')
db = cluster.RolesData
roles = db.RolesCollection

@bot.event
async def on_message(message):
    msg = message.content.lower()
    request = ['роль', 'хочу роль', 'дайте роль', 'нужна роль']

    if msg in request:
        for i in orgs:
            if not message.author.display_name.split(' ')[0].replace('[', '') in orgs:
                await message.channel.send(f'`[ROLES]`: {message.author.mention}, тег организации не найден!')
                break

            if i == message.author.display_name.split(' ')[0].replace('[', ''):
                guild = bot.get_guild(831511376425123882)
                role = discord.utils.get(guild.roles, id=orgs[i])

                await message.channel.send(f'`[ROLES]`: {message.author.mention}, ваш запрос на получение роли был отправлен саппортам!')

                embed = discord.Embed(
                    title='Запрос на получение роли!',
                    description='✅ - выдать роль\n❌ - отклонить запрос\n🖊️ - изменить никнейм\n📋 - запросить статистику',
                    color=0x000000
                )
                embed.add_field(name=f'Пользователь:', value=f'{message.author.mention}', inline=False)
                embed.add_field(name=f'Никнейм:', value=f'{message.author.display_name}', inline=False)
                embed.add_field(name=f'Роль для выдачи:', value=f'{role.mention}', inline=False)
                embed.set_thumbnail(url='https://psv4.userapi.com/c537232/u356224017/docs/d1/416eb92aec38/rodina.png?extra=2E9CwKZ0PIjnG8aaNkwehlHwjxlycBfGx-4p20ABm3mPI4jNpdV1OXaUUA9zGA4Q04VM21UezrXsjtqC411Xbh-Ro7rW1L4OGgNxpcQv3lvfOYCb-Irn-_-51AaQa2fpNDZhHm80dvZm1HlR1ZWoDigw')
                embed.set_image(url=message.author.avatar_url)

                msgemb = await bot.get_channel(851413212485779466).send(embed=embed)

                await msgemb.add_reaction('✅')
                await msgemb.add_reaction('❌')
                await msgemb.add_reaction('🖊️')
                await msgemb.add_reaction('📋')

                roles_post = {
                    'm_id':msg_db.id,
                    'user':msg_db.author
                }

                if roles.count_documents({'m_id':message.id}) == 0:
                    roles.insert_one(roles_post)
                else:
                    await message.channel.send(f'`[ROLES]`: {message.author.mention}, вы уже отправили запрос на получение роли!')

报错输出

Traceback (most recent call last):
  File "C:\Users\Хозяин\AppData\Local\Programs\Python\Python39\lib\site-packages\pymongo\srv_resolver.py", line 89, in _resolve_uri
    results = _resolve(
  File "C:\Users\Хозяин\AppData\Local\Programs\Python\Python39\lib\site-packages\pymongo\srv_resolver.py", line 43, in _resolve
    return resolver.resolve(*args, **kwargs)
  File "C:\Users\Хозяин\AppData\Local\Programs\Python\Python39\lib\site-packages\dns\resolver.py", line 1305, in resolve
    return get_default_resolver().resolve(qname, rdtype, rdclass, tcp, source,
  File "C:\Users\Хозяин\AppData\Local\Programs\Python\Python39\lib\site-packages\dns\resolver.py", line 1176, in resolve
    timeout = self._compute_timeout(start, lifetime)
  File "C:\Users\Хозяин\AppData\Local\Programs\Python\Python39\lib\site-packages\dns\resolver.py", line 997, in _compute_timeout
    raise Timeout(timeout=duration)
dns.exception.Timeout: The DNS operation timed out after 21.201510190963745 seconds

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\Хозяин\Desktop\rodina\main.py", line 5, in <module>
    cluster = MongoClient('mongodb+srv://corry:pa4-pD6-3Dj-AdT@cluster0.gi8x6.mongodb.net/?retryWrites=true&w=majority')
  File "C:\Users\Хозяин\AppData\Local\Programs\Python\Python39\lib\site-packages\pymongo\mongo_client.py", line 704, in __init__
    res = uri_parser.parse_uri(
  File "C:\Users\Хозяин\AppData\Local\Programs\Python\Python39\lib\site-packages\pymongo\uri_parser.py", line 542, in parse_uri
    nodes = dns_resolver.get_hosts()
  File "C:\Users\Хозяин\AppData\Local\Programs\Python\Python39\lib\site-packages\pymongo\srv_resolver.py", line 121, in get_hosts
    _, nodes = self._get_srv_response_and_hosts(True)
  File "C:\Users\Хозяин\AppData\Local\Programs\Python\Python39\lib\site-packages\pymongo\srv_resolver.py", line 101, in _get_srv_response_and_hosts
    results = self._resolve_uri(encapsulate_errors)
  File "C:\Users\Хозяин\AppData\Local\Programs\Python\Python39\lib\site-packages\pymongo\srv_resolver.py", line 97, in _resolve_uri
    raise ConfigurationError(str(exc))
pymongo.errors.ConfigurationError: The DNS operation timed out after 21.201510190963745 seconds
Для продолжения нажмите любую клавишу . . .
问题定位
  • 启动阶段初始化MongoClient连接MongoDB Atlas集群失败,根因是DNS解析操作超时,抛出pymongo.errors.ConfigurationError异常,程序直接终止
  • 业务逻辑中存在未定义变量引用:代码中从未声明msg_db变量,即使数据库连接正常,运行到存储申请记录的逻辑时也会触发NameError
  • 存储逻辑存在设计缺陷:直接存储Discord实体对象会导致序列化异常,重复申请校验维度错误,无法正确拦截同一用户的重复提交
修复方案

1. 解决MongoDB连接DNS超时问题

按优先级依次排查处理:

  • 检查网络拦截规则:确认本地防火墙、系统代理、网络运营商没有拦截对MongoDB Atlas域名的解析和访问,临时关闭防火墙/代理测试连通性
  • 更换本地DNS配置:将系统默认DNS修改为公共DNS(如223.5.5.5、119.29.29.29、8.8.8.8),刷新本地DNS缓存后重试
  • 校验Atlas集群配置:登录MongoDB Atlas控制台,确认集群处于正常运行状态,当前客户端出口公网IP已加入集群IP白名单,数据库账号密码具备对应集合的读写权限
  • 重装兼容版本依赖:执行以下命令安装稳定版pymongo和DNS解析依赖,避免版本兼容问题
pip uninstall -y pymongo dnspython
pip install pymongo[srv]==4.6.3 dnspython==2.6.1

2. 修复业务代码逻辑bug

将存储申请记录部分的代码替换为以下内容,修正未定义变量问题、存储字段问题和重复校验逻辑:

# 发送审批嵌入消息、添加反应完成后
roles_post = {
    'approval_msg_id': msgemb.id,  # 存储审批频道消息ID,用于后续反应事件匹配
    'applicant_user_id': message.author.id,  # 存储申请人用户ID,不要直接存用户对象
    'target_role_id': role.id,  # 额外存储待分配角色ID,方便后续审批逻辑直接使用
    'apply_time': message.created_at
}

# 校验当前用户是否存在待处理申请,避免重复提交
if roles.count_documents({'applicant_user_id': message.author.id, 'status': 'pending'}) == 0:
    roles.insert_one(roles_post)
else:
    await message.channel.send(f'`[ROLES]`: {message.author.mention}, вы уже отправили запрос на получение роли!')

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 11:09:14