Ibrohim.dev
Barcha loyihalar

8-oktabr, 2026

Ops bot

Yonida ishlayotgan tizimni kuzatadigan Telegram bot: guruhlangan xatolar, uzilishlar, deploylar, sertifikatlar va yo‘qolgan backuplar - ishonsa bo‘ladigan darajada jim turadigan qilib qurilgan.

GoPostgreSQLTelegram Bot APIDockercron

Kontekst

Bu saytni bitta VPS’da yolg‘iz o‘zim yuritaman. Navbatchilik jadvali ham, monitoring xizmati ham yo‘q; API tungi ikkida xato qaytara boshlasa, buni bilishi mumkin bo‘lgan yagona odam - men, va faqat biror narsa menga aytsa.

Muammo

Biror narsa buzilganda Telegram’ga xabar yuborish - yarim kunlik ish. Qiyini buning teskarisi: yetarlicha kam xabar yuborish. So‘rov tezligida yiqilayotgan bitta query - daqiqasiga yuzta ogohlantirish, bunday kanal esa birinchi yomon kechadayoq ovozi o‘chirib qo‘yiladi. Shundan keyin navbatdagi haqiqiy uzilish sukutda keladi.

Shuning uchun maqsad hech qachon “hammasini xabar qilish” bo‘lmagan. Maqsad: har bir xabar o‘qishga arziydi, sukut esa hammasi joyida degani.

Qarorlar

Funksiya chaqiruvi emas, outbox jadvali. API va bot - alohida konteynerlar. API Telegram bilan gaplashmaydi; notifications jadvaliga qator qo‘shadi va ishida davom etadi. Jadvalni bot bo‘shatadi. Bot o‘chiq bo‘lsa qator kutadi, Telegram sekin bo‘lsa API buni sezmaydi. Qayta-qayta yiqilayotgan xabar besh urinishdan keyin chetga suriladi - o‘zidan keyingi navbatni to‘sib qo‘ymasin.

Bot bazani to‘g‘ridan-to‘g‘ri o‘qiydi va yozadi. API orqali emas, ataylab: “nima buzildi?” deb so‘rashim eng kerak bo‘lgan payt - API javob bera olmaydigan payt. Uzilishni tuzatish asbobi uzilgan narsaning o‘ziga bog‘liq bo‘lmasligi kerak.

Xatolar e’lon qilinishidan oldin guruhlanadi. Har bir xato marshruti va matnidan - ID va raqamlar olib tashlangan holda - barmoq izi oladi; “post 8f3c… topilmadi” va “post a91b… topilmadi” bitta guruh. Guruh o‘n besh daqiqada ko‘pi bilan bitta xabar beradi, orada nechta bo‘lganini ham aytadi. Alohida kuzatuv uzilishning boshqa shaklini ushlaydi - har biri bir martadan ko‘ringan ko‘p turli xatolar.

Jiddiylik “yuborilsinmi”ni emas, “qachon”ni hal qiladi. Tunda faqat kritik xabarlar kelishi mumkin. 23:00 dan 08:00 gacha yuborilishi kerak bo‘lgan qolgan hammasi 09:00 gacha ushlab turiladi. Tiklanish xabari ham ataylab kritik: uzilish 02:00 da xabar qilinib, tiklanishi ertalabgacha ushlab turilsa, butun kecha uzilgandek ko‘rinardi.

Lipillash yo‘q. Holat hukmi faqat ketma-ket ikki tekshiruv bir xil chiqqandan keyin e’lon qilinadi. Bitta muvaffaqiyatsiz so‘rov odatda yo‘qolgan paket yoki qayta ishga tushayotgan konteyner; shularni xabar qiladigan monitor egasini o‘zini e’tiborsiz qoldirishga o‘rgatadi.

Kuzatuvchini u bilan hech narsasi umumiy bo‘lmagan narsa kuzatadi. Bot o‘lganda sukut aynan sog‘lomlikka o‘xshaydi. Shuning uchun bot puls qatorini yozib turadi, hostdagi cron vazifasi esa - oddiy psql va curl, botsiz, outboxsiz - puls eskirganda Telegram’ga to‘g‘ridan-to‘g‘ri yozadi.

Docker socket yo‘q. Botga host ko‘rinishini berish uni uchta raqam uchun butun stack ustidan root qilardi. Buning o‘rniga host ko‘rsatkichlari, deploylar va backuplar o‘sha jadvalga host va CI tomonidan yoziladi.

Arxitektura

 API ──INSERT──┐
 CI deploy ────┤                        ┌── outbox sikli (10 s) ──► Telegram
 host cron ────┼──► notifications ◄─────┤
 botning o'zi ─┘        (PostgreSQL)    ├── holat kuzatuvi (2 daq) ─► health_checks
                                        ├── rejalashtiruvchi, kunlik va haftalik xulosa
 API xatolari ─► error_groups ◄─────────┤── sertifikat kuzatuvi (12 soat)
                                        └── buyruqlar: /status /xatolar /posts …
 
 host cron ── bot_heartbeat'ni o'qiydi ──► Telegram   (yuqoridagilarning hech biriga bog'liq emas)

Bitta Go binary, API bilan bir xil image ichida qurilgan va boshqa entrypoint bilan ishga tushirilgan.

Kundalik ishi

  • Deploylar, nashr qilingan postlar, aloqa formasidan kelgan xabarlar va yangi taklifnomalar haqida xabar beradi.
  • API xatolari, panic’lar va brauzerdagi xatolarni - guruhlangan va cheklangan holda - yetkazadi.
  • Uchta ommaviy domenni va API’ning ichki manzilini kuzatadi, o‘ttiz kunlik tarixni saqlaydi; shu tufayli /status faqat “hozir ishlayaptimi?”ga emas, “qanday ishlab keldi?”ga ham javob beradi.
  • Sertifikat tugashiga 14, 7 va 3 kun qolganda ogohlantiradi - Caddy o‘zi yangilaydi, demak bu xabar yangilash buzilganini bildiradi.
  • Har tungi backup va uning nusxasi qayerga ketganini xabar qiladi, backup bo‘lmaganini va tashqi nusxa yuborilmaganini payqaydi.
  • Telefondan post qoralamasini yozish, tahrirlash, rejalashtirish va nashr qilish imkonini beradi.

Yozish emas, ishlatish

Ikki narsani faqat uni ishlatib ko‘rganimda o‘rgandim.

Kuzatuvchi ishga tushishidan uch hafta oldin yozilgan edi. Backup, watchdog va host ko‘rsatkichlari skriptlari sentabrda merge qilingan. Serverdagi crontab esa oktabrgacha bo‘sh turdi va hech narsa shikoyat qilmadi - chunki men ataylab “hali birorta ham backup bo‘lmagan” holatini incident emas, sozlash bosqichi deb belgilagandim: sozlash davomida ogohlantirish behuda bong urmasin deb. O‘zicha to‘g‘ri qaror; lekin hech qachon bajarilmagan sozlash qadami bilan birga u aynan shu holat uchun qurilgan yagona ogohlantirishni o‘chirib qo‘ydi. Jim sozlash bosqichining tugash muddati bo‘lishi kerak.

Faqat hujjatda mavjud bo‘lgan sozlama. Tashqi heartbeat - butun server o‘chganda ham ishlaydigan yagona ogohlantirish - “bitta muhit o‘zgaruvchisi” deb yozilgan edi. Compose fayl esa bu o‘zgaruvchini bot konteyneriga umuman uzatmagan: uni o‘rnatish hech narsani o‘zgartirmasdi va buni hech kim aytmasdi.

Ikkalasi ham hozir yopilgan. Cron ishlaydi; har backup 30 kunlik qulfi bor Cloudflare R2 bucket’iga tushadi, shuning uchun buzilgan server ham o‘z tarixini o‘chira olmaydi; o‘sha nusxadan tiklash sinab ko‘rilgan; pinglar to‘xtasa healthchecks.io o‘zining Telegram boti orqali bong uradi.

Bu hamon bitta server va bitta odam. Maqsad hech qachon hech narsa buzilmasligi emas edi. Maqsad - biror narsa buzilganda, bu haqda u bilan birga buzilmagan narsadan eshitish.