Telegram Botda 429 Too Many Requests Xatosi va Redis Bilan Yechim

Muallif: Javohir Abdullayev · · Telegram botlar

Telegram Botda 429 Too Many Requests Xatosi va Redis Bilan Yechim

Kirish: Real loyihadagi kutilmagan to'siq

Yaqinda mijozimizning 20,000 dan ortiq faol foydalanuvchiga ega bo'lgan e-tijorat Telegram botida jiddiy muammo yuzaga keldi. Yangi aksiya e'lon qilingan paytda minglab xaridorlar bir vaqtning o'zida botga kirib, tugmalarni ketma-ket bosa boshladi. Natijada bot javob bermay qoldi va server loglarida mashhur xatolik paydo bo'ldi: TelegramRetryAfter: Flood control exceeded. Retry in 18 seconds (HTTP 429).

Ushbu case study orqali Telegram botlarda so'rovlar chegarasi (Rate Limit) qanday ishlashini, 429 xatosi nima uchun kelib chiqishini va Aiogram 3 hamda Redis yordamida buni qanday bartaraf etishni ko'rib chiqamiz.

Nega Telegram 429 xatosini qaytaradi?

Telegram Bot API serverlari o'z infratuzilmasini spam va haddan tashqari yuklamadan (DDoS) himoya qilish uchun qat'iy cheklovlarga ega:

  • Bitta chatga yuborish limiti: 1 soniyada ko'pi bilan 1 ta xabar (qisqa muddatli ko'tarilishlarda 30 tagacha ruxsat berilishi mumkin, lekin doimiy emas).
  • Umumiy xabarlar limiti: Barcha chatlarga jami 1 soniyada ko'pi bilan 30 ta xabar.
  • Guruhlarga xabar yuborish: 1 daqiqada ko'pi bilan 20 ta xabar.

Agar sizning botingiz ushbu limitlardan oshib ketsa, Telegram API 429 Too Many Requests xatosi bilan birga qancha soniya kutish kerakligini (retry_after) bildiradi. Agar buni to'g'ri boshqarmasangiz, barcha foydalanuvchilar uchun bot qotib qoladi.

Muammoni tahlil qilish: Xatolik qayerda edi?

Loyiha kodini tahlil qilganimizda ikkita asosiy kamchilik aniqlandi:

  1. Foydalanuvchi spami: Ayrim foydalanuvchilar bitta tugmani 1 soniyada 5-10 marta bosganida bot har biriga alohida API so'rovi yuborayotgan edi.
  2. Xotira holati (In-Memory State): Rate limit tekshiruvi Python xotirasida (dictionary) saqlangani sababli, bot qayta ishga tushganda yoki bir nechta worker'lar ishlaganda sinxronlik yo'qolar edi.

Yechim: Redis yordamida Throttling Middleware yaratish

Muammoni hal qilish uchun har bir foydalanuvchining so'rovlar chastotasini Redis orqali nazorat qiluvchi maxsus middleware yozdik. Redis juda tez ishlaydi va kalitlarga avtomatik o'chish vaqti (TTL) belgilash imkonini beradi.

1. Redis bilan ishlovchi Throttling Middleware kodi

Aiogram 3 uchun BaseMiddleware asosida yaratilgan klassimiz quyidagicha:

from typing import Any, Awaitable, Callable, Dict
from aiogram import BaseMiddleware
from aiogram.types import TelegramObject, Message, CallbackQuery
import redis.asyncio as aioredis

class ThrottlingMiddleware(BaseMiddleware):
    def __init__(self, redis: aioredis.Redis, limit_seconds: int = 1):
        self.redis = redis
        self.limit_seconds = limit_seconds

    async def __call__(
        self,
        handler: Callable[[TelegramObject, Dict[str, Any]], Awaitable[Any]],
        event: TelegramObject,
        data: Dict[str, Any]
    ) -> Any:
        user = data.get("event_from_user")
        if not user:
            return await handler(event, data)

        user_id = user.id
        key = f"throttle:{user_id}"
        
        # Redis ichida kalit mavjudligini tekshiramiz
        is_throttled = await self.redis.get(key)
        
        if is_throttled:
            # Agar foydalanuvchi belgilangan vaqtdan tez bosgan bo'lsa
            if isinstance(event, CallbackQuery):
                await event.answer("Iltimos, shoshilmang!", show_alert=False)
            elif isinstance(event, Message):
                # Keraksiz xabarlarni e'tiborsiz qoldiramiz yoki ogohlantiramiz
                pass
            return
        
        # Kalitni belgilangan muddatga (TTL) saqlaymiz
        await self.redis.set(key, "1", ex=self.limit_seconds)
        return await handler(event, data)

2. Middleware'ni botga ulash

Asosiy main.py faylida Redis ulanishini hosil qilib, middleware'ni ro'yxatdan o'tkazamiz:

import asyncio
from aiogram import Bot, Dispatcher
import redis.asyncio as aioredis
from config import BOT_TOKEN, REDIS_URL
from middlewares import ThrottlingMiddleware

async def main():
    bot = Bot(token=BOT_TOKEN)
    dp = Dispatcher()
    
    redis = aioredis.from_url(REDIS_URL, decode_responses=True)
    
    # Xabarlar va Callback so'rovlar uchun throttling yoqamiz
    dp.message.middleware(ThrottlingMiddleware(redis=redis, limit_seconds=1))
    dp.callback_query.middleware(ThrottlingMiddleware(redis=redis, limit_seconds=1))
    
    await dp.start_polling(bot)

if __name__ == "__main__":
    asyncio.run(main())

Ommaviy xabarnomalar (Broadcast) muammosi

Foydalanuvchilarga xabar tarqatishda 429 xatosiga tushmaslik uchun oddiy for siklidan voz kechish kerak. Buning o'rniga xabarlar o'rtasida mikro-pauza (asyncio.sleep(0.05)) qo'yish va TelegramRetryAfter xatosi tushganda avtomatik kutish mantiqini yozish zarur:

from aiogram.exceptions import TelegramRetryAfter, TelegramForbiddenError
import asyncio
import logging

async def send_broadcast_message(bot: Bot, user_id: int, text: str):
    try:
        await bot.send_message(chat_id=user_id, text=text)
        await asyncio.sleep(0.05)  # Sekundiga 20 tagacha xabar yuborish xavfsiz
    except TelegramRetryAfter as e:
        logging.warning(f"{e.retry_after} soniya kutish kerak...")
        await asyncio.sleep(e.retry_after)
        return await send_broadcast_message(bot, user_id, text)
    except TelegramForbiddenError:
        logging.info(f"Foydalanuvchi botni bloklagan: {user_id}")
    except Exception as e:
        logging.error(f"Kutilmagan xatolik: {e}")

Natija va Xulosa

Ushbu o'zgarishlardan so'ng botdagi ko'rsatkichlar tubdan yaxshilandi:

  • 429 xatolari 99% ga kamaydi: Foydalanuvchilar tugmalarni qayta-qayta bosganda so'rovlar Telegram API'ga yetib bormasdan Redis darajasida to'xtatildi.
  • Server resurslari tejaldi: Qayta ishlanmaydigan ortiqcha DB so'rovlari yo'qoldi.
  • Foydalanuvchi tajribasi (UX) oshdi: Bot barcha foydalanuvchilar uchun bir tekis va barqaror ishlay boshladi.

Agar siz ham yuqori yuklamali Telegram botlar yaratayotgan bo'lsangiz, albatta boshidanoq Redis asosidagi Throttling va Rate Limiting tizimini joriy qiling.

Teglar: #Telegram bot #Aiogram 3 #Redis #Python #Rate limiting