@llimonix

Бот дискорда падает в Rate limited, что делать?

У меня бот почти 4000 серверов. По формуле КОЛИЧЕСТВО СЕРВЕРОВ / 1000 = КОЛИЧЕСТВО ШАРДОВ
Бот должен быть запущен на 4-5 шардах. Но при запуске на таких шардах у меня сразу же вылазит таймаут на несколько минут из за Rate limited, именно во время запуска

Ставлю 128 шардов у меня все норм, но во время работы бота вылазит
[2024-03-27 17:05:25] [WARNING ] discord.http: We are being rate limited. PATCH https://discord.com/api/v10/channels/1215300998588... responded with 429. Retrying in 2.08 seconds.
[2024-03-27 17:05:30] [WARNING ] discord.http: We are being rate limited. PATCH https://discord.com/api/v10/channels/1215300998588... responded with 429. Retrying in 3.78 seconds.

Но 128 шардов для такого маленького бота это очень много. Когда у другого музыкального бота, 250к серверов и у него 128 шардов

Что я делаю не так. Говорили мне, что бот где то спамит. Но я пересмотрел весь код, ну нету ничего такого

В кратце о боте:
Музыкальный бот использующий discord.py и wavelink. Так же имеется запущенный сервер lavalink

Main функция с шардированием

import asyncio
import logging

import discord
from discord.ext import commands, tasks
from itertools import cycle

import wavelink

from bot.utils.database import db


class Bot(commands.AutoShardedBot):
    def __init__(self) -> None:
        intents: discord.Intents = discord.Intents.default()
        intents.members = True
        #intents.messages = True

        discord.utils.setup_logging(level=logging.INFO)
        super().__init__(command_prefix="?", intents=intents, help_command=None)

    async def setup_hook(self) -> None:
        nodes = [wavelink.Node(uri="http://localhost:1337", password="pass")]

        # cache_capacity is EXPERIMENTAL. Turn it off by passing None
        await wavelink.Pool.connect(nodes=nodes, client=self)

    async def on_ready(self) -> None:
        await db.create_table()
        await self.tree.sync()
        logging.info(f"Logged in: {self.user} | {self.user.id}")
        await change_status.start()


bot: Bot = Bot()
bot.shard_count = 128

async def main() -> None:
    async with bot:
        await load_extension()
        await bot.start("TOKEN")

async def load_extension():
    await bot.load_extension("bot.interactions")
    await bot.load_extension("bot.core")

status = cycle(['Басы на максимуме...', 'Музыкальный режим...', 'Бот-Ди-Джей в деле...', 'Бот на волне...',
                'Мелодии в эфире...', 'Ритмы и вибрации', 'Слушай и расслабляйся...', 'Твой звуковой компаньон.',
                'Твой персональный DJ.', 'Биты и басы в эфире.', 'Бот-Диджей готов к действию.',
                'Твои любимые мелодии здесь!', 'Музыкальный калейдоскоп в твоем дискорде.', 'Виртуозный бот в деле.'])
@tasks.loop(seconds=10)
async def change_status():
    await bot.change_presence(activity=discord.Activity(type=discord.ActivityType.listening, name=next(status)))

asyncio.run(main())
  • Вопрос задан
  • 500 просмотров
Решения вопроса 1
fenrir1121
@fenrir1121 Куратор тега discord.py
Начни с документации
Давайте по порядку. В документации дискорда очень четко прописаны лимиты для вебсокета и чуть менее четко для HTTP. Цитировать оттуда не буду, думаю там все понятно.

В общем виде ошибка 429 говорит, что в один из двух лимитов вы не укладываетесь. Чтобы не происходила ошибка можно перед выполнением действий проверять блокировку через AutoShardedClient.is_ws_ratelimited, но это не лечение проблемы, а только обработка.
Для лечения нужно перехватывать ошибку в глобальном обработчике и по стеку вызовов смотреть на каком действии она происходит. Если приложите стектрейс к запросу, можно будет по нему сказать конкретнее. Только убедитесь чтобы логи не обрезались как у вас выше. Может быть и так было бы понятно, но эндпоинт https://discord.com/api/v10/channels/1215300998588... весь не видно. Учитывайте что она может и в разных когах происходить об этом ниже.

В целом дискорд не любит, когда боты делают что-либо без явных действий пользователя. Причем чем больше бот, тем строже, поскольку для них это больше нагрузки. К примеру в коде, который вы приложили есть обновление статуса каждые 10 секунд. Будем объективны, пользователям плевать что у бота в статусе, но эти запросы так же идут в общий рейт лимит. Я бы советовал поставить или большое значение (5-10 минут) или вообще избавиться от этой карусели.
Аналогично пройдите по остальному коду, который не приложен и посмотрите есть ли периодические запросы без явных команд: например обновления каких-нибудь сообщений по таймерам. Если есть увеличивайте таймеры в 2 раза (повторять до исправления) или подумайте как предоставлять функционал без этого.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы