Asosiy kontentga o‘tish

Maqolalar 8 daqiqa 86 ko‘rish

nohup emas, systemd: bot serverda qanday qilib 24/7 yashaydi

«nohup python app.py &» bilan ishga tushirilgan bot server reboot bo'lgan kuni jimgina o'ladi — va buni birinchi bo'lib mijoz sezadi. Botni systemd xizmatiga aylantiramiz: o'zi qayta ko'tariladi, reboot'dan omon chiqadi, loglari bir joyda turadi.

telegram-bot linux devops

Mundarija

Bu qismni real voqea bilan boshlayman. Yaqinda serverga reboot berildi. Saytlar ko'tarildi, systemd ostidagi xizmatlar ko'tarildi — lekin bitta bot jim qoldi. Sababi oddiy ekan: u yillar oldin nohup python app.py & bilan ishga tushirilgan va shu holicha ishlab yurgan. nohup jarayonni terminal yopilishidan asraydi, ammo reboot'dan asramaydi. Bot o'ldi, hech qanday ogohlantirish kelmadi, uzilishni birinchi bo'lib foydalanuvchi payqadi.

Bunday holatga qayta tushmaslik uchun bot oddiy jarayon emas, tizim xizmati bo'lishi kerak. Linux'da buning standart yo'li — systemd. Keling, Aladdin botini misol qilib, uni boshdan-oyoq systemd xizmatiga aylantiramiz.

Boshlashdan oldin: foydalanuvchi va papka#

Bot alohida tizim foydalanuvchisi nomidan ishlaydi. Bu foydalanuvchi serverga login qila olmaydi — uning yagona vazifasi botni ko'tarish:

Terminal
sudo useradd --system --home-dir /opt/aladdin_bot --shell /usr/sbin/nologin botuser

# loyiha /opt/aladdin_bot da: ichida oldingi qismlardagi bot/ paketi,
# kutubxonalar (aiogram va boshqalar) esa .venv ichida; keyin egasini almashtiramiz:
sudo chown -R botuser:botuser /opt/aladdin_bot
ls /opt/aladdin_bot/.venv/bin/python /opt/aladdin_bot/bot/app.py   # ikkalasi ham ko'rinishi kerak

Unit fayl: xizmatning pasporti#

systemd xizmati bitta matnli fayl bilan tavsiflanadi. Uni /etc/systemd/system/ papkasiga qo'yamiz:

INI
# /etc/systemd/system/aladdin_bot.service
[Unit]
Description=Aladdin Catalog Telegram Bot
# tarmoq ko'tarilmaguncha botni boshlamaymiz — aks holda birinchi
# so'rovlar "connection refused" bilan yiqiladi
After=network-online.target
Wants=network-online.target
# qayta urinishlar soniga cheklov qo'ymaymiz — pastda tushuntiraman
StartLimitIntervalSec=0

[Service]
Type=simple
# alohida foydalanuvchi: bot root bo'lib ishlamasligi kerak
User=botuser
WorkingDirectory=/opt/aladdin_bot
# sirlar unit faylda emas, .env faylda turadi (pastda tushuntiraman)
EnvironmentFile=/opt/aladdin_bot/.env
# print() chiqishi jurnalga darhol tushsin (pastda tushuntiraman)
Environment=PYTHONUNBUFFERED=1
# 2-qismdagidek paket sifatida: "python bot/app.py" import'larda yiqiladi
ExecStart=/opt/aladdin_bot/.venv/bin/python -m bot.app

# yiqilsa — 5 soniyadan keyin o'zi turadi; ketma-ket yiqilsa kutish asta
# uzayib boradi (5, 8, 13, 22... soniya), lekin 60 soniyadan oshmaydi
Restart=always
RestartSec=5
RestartSteps=5
RestartMaxDelaySec=60

[Install]
# multi-user.target'ga "ilingan" xizmat reboot'dan keyin avtomatik ko'tariladi
WantedBy=multi-user.target

Har satrning vazifasi izohda yozilgan, lekin uchta eng muhimini alohida ta'kidlayman: Restart=always botni yiqilganda turg'izadi, WantedBy esa reboot'dan keyin ishga tushiradi — ikkalasi birga bo'lgandagina bot chinakam 24/7 bo'ladi. User=botuser esa xavfsizlik odati: bot buzilsa ham, buzgan odam root emas, oddiy foydalanuvchi huquqida qoladi.

«1 daqiqada 5 marta yiqilsa — to'xtasin» degan tuzoq

Ko'p qo'llanmalarda StartLimitIntervalSec=60 va StartLimitBurst=5 tavsiya qilinadi: buzuq deploy cheksiz qayta urinmasin, deb. Ikki narsani bilib qo'ying. Birinchidan, bu qatorlar [Unit] bo'limida turishi shart — [Service] ga yozilsa, systemd Unknown key name 'StartLimitIntervalSec' deb interval'ni jimgina tashlab yuboradi. Ikkinchidan, to'g'ri joyda bu cheklov "to'xtab turish" emas, butunlay taslim bo'lish: limitga yetgan xizmat failed holatda qoladi va sabab yo'qolgach ham o'zi qaytmaydi — sudo systemctl reset-failed aladdin_bot va qayta start kerak. Sinovda Telegram API'ga yarim daqiqa ulana olmagan bot aynan shunday abadiy o'ldi. 24/7 bot uchun yaxshirog'i yuqoridagi yo'l: cheklov o'chiq, kutish esa RestartSteps va RestartMaxDelaySec bilan o'sib boradi — buzuq deploy serverni qiynamaydi, tarmoq tiklangach bot o'zi qaytadi.

RestartSteps va RestartMaxDelaySec systemd 254 dan beri bor (Ubuntu 24.04 da 255). Eskiroq tizimda (masalan Debian 12) ular Unknown key bilan e'tiborsiz qoladi va bot shunchaki har 5 soniyada qayta urinadi — bu ham ishlaydigan holat. Versiyani systemctl --version ko'rsatadi.

Ishga tushirish: uch buyruq#

Terminal
# unit faylni o'qitamiz (har tahrirdan keyin ham shu kerak)
sudo systemctl daemon-reload

# hozir ishga tushirish + reboot ro'yxatiga qo'shish, bitta buyruqda
sudo systemctl enable --now aladdin_bot

# holatini ko'ramiz
sudo systemctl status aladdin_bot

status chiqishida Active: active (running) va enabled so'zlarini ko'rsangiz — bo'ldi, bot endi xizmat. enabled aynan reboot'dan keyin ko'tarilishni anglatadi; active bo'lib turgan, lekin disabled xizmat keyingi reboot'da yana jim qoladi — yuqoridagi voqeadagi xatoning o'zi.

Loglar: nohup.out o'rniga journalctl#

nohup davrida loglar nohup.out degan faylga oqib borardi — u nazoratsiz o'sadi va hech kim uni o'qimaydi. systemd'da esa stdout'ga yozilgan har narsa avtomatik jurnalga tushadi. Ya'ni bot kodida oddiy print yoki logging.StreamHandler yetarli, fayl bilan ishlash umuman shart emas.

Faqat print bilan bitta nozik joy bor — unit'dagi PYTHONUNBUFFERED=1 qatori shuning uchun. Terminalda Python har print ni darhol chiqaradi, jurnalga yozganda esa chiqishni buferda yig'ib turadi. Sinovda bu qatorsiz botning print xabarlari jurnalga umuman tushmadi — jarayon o'ldirilganda bufer ham birga yo'qoldi. logging modulining xabarlari esa (aiogram ham shu orqali yozadi) buferlanmaydi.

Terminal
# jonli oqim (Ctrl+C bilan chiqiladi)
sudo journalctl -u aladdin_bot -f

# oxirgi soatdagi Python xatolari (traceback'lar)
sudo journalctl -u aladdin_bot --since "1 hour ago" -g "traceback|error"

# kecha kechqurun nima bo'lgani
sudo journalctl -u aladdin_bot --since "yesterday 18:00" --until "yesterday 23:00"

Log fayl emas, oqim

Ilova o'z logini faylga yozmasin — shunchaki stdout'ga chiqarsin, qolganini tizim hal qiladi. Bu 12-factor tamoyillaridan biri va systemd bilan u o'z-o'zidan ishlaydi: rotatsiya, saqlash muddati, qidiruv — hammasi journald zimmasida.

Sirlar: EnvironmentFile#

Bot tokeni, API kalitlari unit faylga yozilmaydi, chunki unit fayl /etc/systemd/system/da hamma o'qiy oladigan joyda turadi. Ular alohida faylga chiqariladi:

Terminal
# /opt/aladdin_bot/.env
BOT_TOKEN=1234567890:AAF...
CATALOG_API_URL=https://catalog.misol.uz/api/telegram
Terminal
# faqat egasi o'qiy oladi:
sudo chown botuser:botuser /opt/aladdin_bot/.env
sudo chmod 600 /opt/aladdin_bot/.env

EnvironmentFile= qatori tufayli bu o'zgaruvchilar botga muhit orqali yetib boradi — kodda os.environ["BOT_TOKEN"] deb o'qiladi, fayl yo'li haqida bot hech narsa bilmaydi.

Ishonch hosil qilish: ikkita sinov#

Sozlab bo'ldik — endi haqiqatan ishlashini tekshiramiz. Birinchi sinov, jarayonni ataylab o'ldiramiz:

Terminal
sudo pkill -f "bot.app"
sleep 6
sudo systemctl status aladdin_bot   # yana active (running) bo'lishi kerak

Ikkinchi sinov — reboot'ning o'zi. Buni "qachondir kerak bo'lganda" emas, sozlagan kuningiz qiling: sudo reboot, bir daqiqadan keyin ulanib systemctl status qarang. Ishlayaptimi — endi kechasi ham, ta'tilda ham xotirjam uxlayverasiz. Bizning holatda aynan shu sinov qilinmagani uchun bot yillar o'tib "jim o'lgan" edi.

Restart har dardga davo emas

Restart=always yiqilgan botni turg'izadi, lekin nega yiqilganini aytmaydi. Bot har besh daqiqada qayta tug'ilib ishlayotgan bo'lishi ham mumkin — tashqaridan hammasi joyida ko'rinadi. Vaqti-vaqti bilan systemctl show aladdin_bot -p NRestarts va sudo journalctl -u aladdin_bot -g traceback --since today qarab turing (-p err bu yerda yordam bermaydi — botning chiqishi jurnalga oddiy info darajasida tushadi), yoki yaxshisi, xatolarni adminga yuboradigan bildirishnoma qo'shing — Humo seriyasida shunga o'xshash yondashuvni ko'rgan edik.

Xulosa#

Botni serverda uzoq yashatishning retsepti qisqa: nohup unutiladi, o'rniga bitta unit fayl yoziladi. Unda uchta narsa hal qiluvchi — Restart=always (yiqilsa turadi), WantedBy=multi-user.target + enable (reboot'dan omon chiqadi) va EnvironmentFile (sirlar o'z joyida). Loglar journalctl'da, sinov esa sozlagan kuni qilinadi, keyinga qoldirilmaydi.

Shu bilan Aladdin bot amaliyoti seriyasi yakunlandi: backend'dan ajratilgan katalog, adashtirmaydigan navigatsiya, uch til va o'lmas xizmat — besh yildan beri ishlab turgan botning to'liq retsepti. Server sozlashning qolgan qismi — nginx, TLS, backup va boshqalar — alohida DevOps seriyasida davom etadi.

8 daqiqa 86 marta o‘qildi