Tarkibga o'tish

Ishonchlilik va parallellik

Botni ishlab chiqarishda tirik saqlaydigan narsa: beqaror tarmoqda yiqilmaslik, Telegram'ning flood limitlariga urilmaslik, va yangilanishlar to'planganda boringizdagi yadrolardan foydalanish.

Qayta urinishlar avtomatik

Har API chaqiruvi retry qatlamidan o'tadi. Tarmoq xatolari, HTTP 5xx va 429 rate-limit'lar qisqa backoff bilan qayta uriniladi; 429 taxmin qilish o'rniga Telegram yuborgan retry_after qiymatini hurmat qiladi. Doimiy mijoz xatolari (400, 401, 403, 404) darhol ko'tariladi, chunki ularni qayta urinish hech qachon yordam bermaydi.

Buni siz hech sozlamaysiz. U JSON chaqiruvlari uchun ham, fayl yuklash uchun ham standart yoniq. Hatto JSON ham bo'lmagan javob (curl uzilishi, kesilgan tana) vaqtinchalik xato deb hisoblanadi, shuning uchun bitta yomon o'qish chaqiruvni qulatmaydi.

Xatolarni boshqarish

API chaqiruvlari doimiy xatoda ko'tariladi, shuning uchun xato berishi mumkin bo'lganlarini o'rab, nima qilishni hal qiling. Poll siklida har yangilanish uchun ushlang, shunda bitta yomon handler jarayonni o'ldirmaydi:

while True:
    var ups = dp.poll()
    for i in range(ups.len()):
        try:
            handle(dp.context(Update(ups.at(i))))
        except e:
            # log qiling va xizmatda qoling
            print("handler xatosi:", e)

Xato xabari Telegram'ning kodi va tavsifini olib keladi, masalan Telegram API error [400] on sendMessage: chat not found, shuning uchun bitta log qatori odatda nima noto'g'ri ketganini ko'rish uchun yetarli.

Rate limiting

Telegram sizni umumiy taxminan soniyasiga 30 xabar, va bitta chatga taxminan soniyasiga bitta xabar bilan cheklaydi. Undan oshib ketsangiz, 429 olasiz. Retry qatlami vaqti-vaqti bilan keladigan 429'ni yutadi, lekin zich siklda yuborayotgan bo'lsangiz, o'z tomoningizda RateLimiter bilan tezlikni ushlang. U token bucket: acquire() tezlik ostida qolish uchun yetarlicha bloklaydi.

from mojogram import RateLimiter

# 25 msg/s, chegaradan bir oz past
var limiter = RateLimiter(rate=25.0, burst=25.0)

for chat_id in chat_ids:
    # juda tez ketsak, kutadi
    limiter.acquire()
    _ = bot.send_message(chat_id, "broadcast")

U thread-xavfsiz (ichida Atomic spinlock), shuning uchun bitta limiter'ni parallel ishchilar bo'ylab ulashsa bo'ladi.

Parallel to'plamlar

Mojo 1.0'da threadlar yo'q, lekin parallelize bor, GIL'siz thread-pool ustida parallel-for. mojogram undan poll to'plamini yadrolar bo'ylab ishlash uchun foydalanadi, shunda bitta sekin handler qolganlarini ushlab qolmaydi. Bu ixtiyoriy; standart sikl ketma-ket.

from std.algorithm import parallelize

var ups = dp.poll()
var n = ups.len()

@parameter
def worker(i: Int):
    try:
        # i ni slot sifatida bering
        handle(dp.context(Update(ups.at(i)), i))
    except e:
        print(e)

parallelize[worker](n)

Buni ikki narsa xavfsiz qiladi. Ishchi indeksini slot sifatida berish har ishchiga o'z HTTP vaqtinchalik fayllarini beradi, shunda parallel curl chaqiruvlari bir-birini buzmaydi. Va FSM store o'z maplarini spinlock bilan himoyalaydi, shunda ulashilgan holatga tegayotgan ishchilar uni buza olmaydi. Lock faqat Dict op'ning mikrosoniyalariga ushlanadi, hech qachon handler tarmoq chaqiruvi bo'ylab emas, shuning uchun parallellik haqiqiy. U 500 ta distinct-key yozuv (hech biri yo'qolmaydi) va 1000 ta contended read-modify-write (aniq) bilan sinaldi.

Bitta eslatma: store torn holatdan himoya qiladi, lekin bir xil chat uchun get-then-set baribir ikki operatsiya. Bu bir-chatga-bir-yangilanish FSM oqimlari uchun yetarli, ya'ni odatiy holat.

Bir nechta tilda gapirish

I18n kichik tarjima katalogi. Satrlaringizni har locale uchun qo'shing, keyin ularni fallback bilan qidiring: so'ralgan locale, keyin standart locale, keyin siz bergan fallback matn.

from mojogram import I18n

var i18n = I18n(default_locale="en")
i18n.add("en", "hello", "Hello")
i18n.add("uz", "hello", "Salom")

var lang = msg.from_user().language_code()    # "uz", "en", ...
_ = ctx.answer(i18n.t(lang, "hello", "Hello"))

language_code() to'g'ridan foydalanuvchidan keladi, shuning uchun locale'ni so'ramasdan har bir odam uchun tanlasa bo'ladi.