API sekin ishlay boshlaganda birinchi xayolga keladigan narsa — serverni kuchaytirish. Ko'pincha muammo boshqa joyda: so'rov ichida bajarilmasligi kerak bo'lgan ishlar bajarilyapti. Xat yuborish, Telegram'ga xabar, rasm qayta ishlash, tashqi API'ga murojaat — bularning hech biri foydalanuvchi javobni kutib turishiga arziydi. Bu maqolada Django va Celery bilan shunday ishlarni fonga qanday chiqarishimni, WeliCoDev va NutriZone'dagi amaliy misollar bilan ko'rsataman.
1. Qoida: so'rov — faqat javob uchun
HTTP so'rov ichida faqat foydalanuvchiga javob qaytarish uchun zarur bo'lgan ish qolishi kerak: tekshiruv, bazaga yozish, javob. Qolgan hammasi — navbatga. Arxitektura oddiy:
- Django — so'rovni qabul qiladi va vazifani navbatga qo'yadi;
- Redis — broker: vazifalar navbati;
- Celery worker — vazifalarni fonda bajaradi;
- Celery beat — jadval bo'yicha ishlar (har daqiqa, har kuni).
2. Eng ko'p uchraydigan xato: tranzaksiya tugamasdan vazifa yuborish
Model saqlangan zahoti task.delay(obj.pk) chaqirsangiz, worker obyektni bazadan topa olmasligi mumkin — chunki tranzaksiya hali commit qilinmagan. Yechim — transaction.on_commit:
from django.db import transaction
def on_article_published(instance):
transaction.on_commit(
lambda: post_to_channel.delay("blog.Article", instance.pk)
)
Shu bilan vazifa faqat ma'lumot haqiqatan saqlangandan keyin navbatga tushadi.
3. Idempotentlik: vazifa ikki marta ishlasa ham zarar yo'q
Celery vazifani qayta urinishi (retry) yoki worker qayta ishga tushishi mumkin. Shuning uchun har bir vazifa “ikki marta bajarilsa nima bo'ladi?” degan savolga javob berishi kerak. Kanalga post yuborishda men ikki himoya qo'yaman: obyektdagi belgi va yuborilgan postlar jadvali.
@shared_task
def post_to_channel(model_label, pk):
obj = Model.objects.filter(pk=pk).first()
if obj is None or obj.posted_to_channel_at:
return # allaqachon yuborilgan
if ChannelPost.objects.filter(object_id=pk, status="sent").exists():
return
post = channel.post_object(obj)
if post.status == "sent":
Model.objects.filter(pk=pk).update(posted_to_channel_at=timezone.now())
E'tibor bering: vazifaga obyektning o'zi emas, faqat pk uzatiladi. Vazifa bajarilganda eng yangi holat bazadan o'qiladi.
4. Tashqi API limitlari va qayta urinish
Telegram bitta bot uchun soniyasiga taxminan 25 ta xabarga ruxsat beradi. Ommaviy xabar yuborishda buni hisobga olmasangiz, 429 xatolarini olasiz. Ikki qoida:
- yuborish tezligini cheklash (xabarlar orasida qisqa pauza);
- vaqtinchalik xatolarda
retry, doimiy xatolarda (masalan, foydalanuvchi botni bloklagan — 403) to'xtash va buni bazaga yozib qo'yish.
@shared_task(bind=True, max_retries=3, default_retry_delay=10)
def notify_admins(self, text):
for chat_id in admin_chat_ids():
try:
api.send_message(chat_id, text)
except api.TelegramError as e:
log.warning("notify failed for %s: %s", chat_id, e)
5. Jadval bo'yicha ishlar: Celery beat
Rejalashtirilgan kanal postlari va ommaviy xabarlar uchun cron emas, Celery beat ishlataman — jadval kod bilan birga versiyalanadi:
CELERY_BEAT_SCHEDULE = {
"send-due-telegram-posts": {
"task": "apps.telegram_bot.tasks.send_due",
"schedule": 60.0,
},
"nudge-learners": {
"task": "apps.telegram_bot.tasks.nudge_learners",
"schedule": crontab(hour=11, minute=0),
},
}
CELERY_TIMEZONE ni loyiha vaqt zonasiga (bizda Asia/Tashkent) tenglashtirishni unutmang, aks holda “soat 11:00” UTC bo'yicha ishlaydi.
6. Production'da: alohida konteynerlar
Docker Compose'da web, worker va beat — bitta image'dan, lekin alohida servislar. Worker'ni web'dan mustaqil kengaytirish mumkin, beat esa doim bitta nusxada bo'lishi shart (aks holda vazifalar ikki marta yuboriladi).
services:
web:
command: gunicorn config.wsgi -w 3 -b 0.0.0.0:8000
celery-worker:
command: celery -A config worker -l info
celery-beat:
command: celery -A config beat -l info
7. Tekshiruv ro'yxati
- Vazifaga faqat ID uzating, obyekt emas.
- Model saqlangandan keyin —
transaction.on_commit. - Har bir vazifa idempotent bo'lsin.
- Tashqi API limitlari va 4xx/5xx xatolarini alohida ko'ring.
- Beat — faqat bitta nusxa.
- Testlarda tashqi API'ni mock qiling va “ikki marta chaqirildi” holatini tekshiring.
Xulosa
Celery murakkab texnologiya emas, lekin uni to'g'ri ishlatish intizom talab qiladi. So'rovni yengil tuting, og'ir ishni navbatga bering va har bir vazifani qayta bajarilishga tayyor qilib yozing — API o'z-o'zidan tez va barqaror bo'ladi.