Tarkibga o'tish

systemd timer’lar: cron’ga muqobil

cron asoslari va crontab va tizim cron’i maqolalarida cron ko'rib chiqildi — o'nlab yillardan beri ishlatib kelinayotgan oddiy va ishonchli vosita. systemd allaqachon PID 1 sifatida ishlayotgan tizimda uning muqobili bor: systemd timer. U cron bilan bir xil ishni — buyruqni jadval bo'yicha ishga tushirishni — bajaradi, lekin buni journalctl, unit bog'liqliklari va resurs boshqaruvi bilan integratsiyalashgan systemd unit sifatida qiladi.

Bu maqola cron "noto'g'ri" ekanini isbotlash uchun yozilmagan. U ikkalasi o'rtasidagi amaliy farqlarni ko'rsatib beradi, shunda ular orasidan ongli tanlov qilish mumkin bo'ladi.

Nimalarni o'rganasiz

Bu maqola oxirida siz quyidagilarni qila olasiz:

  • systemd timer ikkita fayldan — .service va .timer dan — iborat ekanini tushuntirish;
  • OnCalendar= yordamida cron’ga o'xshash jadval yozish;
  • cron ifodalay olmaydigan jadvallar uchun interval (monotonic) timer’lar — OnBootSec= va OnUnitActiveSec= — dan foydalanish;
  • RandomizedDelaySec= va AccuracySec= bilan serverlar parki yuklamasini taqsimlash va ishga tushish aniqligini boshqarish;
  • yangi timer’ni yoqish, uning holatini va keyingi ishga tushish vaqtini tekshirish;
  • timer chiqishini journalctl orqali ko'rish va hech qachon ishga tushmayotgan timer’ni diagnostika qilish;
  • qachon cron yaxshiroq tanlov, qachon systemd timer ekanini hal qilish.

Bitta qator o'rniga ikkita fayl

cron’da jadval va buyruq bitta qatorda birga yoziladi. systemd timer esa ikkita alohida unit fayldan iborat:

mytask.service   — what needs to run
mytask.timer     — when it needs to run

Bu ajratishning afzalligi: mytask.service ni jadvaldan mustaqil ravishda, istalgan vaqtda qo'lda ishga tushirish mumkin (systemctl start mytask.service). Bu sinov uchun yoki qo'lda qayta ishga tushirish uchun qulay.

Misol: har kuni log'larni tozalash

1. Service faylini yaratish

sudo nano /etc/systemd/system/log-cleanup.service
[Unit]
Description=Clean up old logs

[Service]
Type=oneshot
ExecStart=/usr/local/bin/log-cleanup.sh

Type=oneshot systemd’ga bu unit doimiy ishlaydigan servis emas, balki bir marta ishga tushib tugaydigan vazifa ekanini aytadi. Bu turdagi unit odatda o'z-o'zidan ishga tushirilmaydi — u timer tomonidan ishga tushirilishi uchun mo'ljallangan.

2. Timer faylini yaratish

sudo nano /etc/systemd/system/log-cleanup.timer
[Unit]
Description=Daily schedule for log-cleanup.service

[Timer]
OnCalendar=daily
Persistent=true

[Install]
WantedBy=timers.target
  • OnCalendar=daily — har kuni soat 00:00 da bir marta ishga tushirish (daily — *-*-* 00:00:00 ning qisqartmasi);
  • Persistent=true — agar server o'chiq bo'lgan bo'lsa yoki timer’ning rejalashtirilgan vaqti biror sabab bilan o'tkazib yuborilgan bo'lsa, o'tkazib yuborilgan ishga tushirish tizim qayta yoqilishi bilanoq bajariladi (cron’da bunga teng xatti-harakat yo'q).

OnCalendar= cron ifodasiga qaraganda o'qilishi osonroq sintaksisdan foydalanadi:

Maqsad OnCalendar= qiymati Taxminiy cron ekvivalenti
Har kuni yarim tunda daily yoki *-*-* 00:00:00 0 0 * * *
Har soatda hourly 0 * * * *
Har dushanba soat 03:00 da Mon *-*-* 03:00:00 0 3 * * 1
Har oyning 1-kuni soat 04:30 da *-*-01 04:30:00 30 4 1 * *

OnCalendar= ifodasini haqiqiy timer’ga ulashdan oldin tekshirib ko'rish mumkin:

systemd-analyze calendar 'Mon *-*-* 03:00:00'
  Original form: Mon *-*-* 03:00:00
Normalized form: Mon *-*-* 03:00:00
    Next elapse: Mon 2026-07-27 03:00:00 UTC

Next elapse ifoda haqiqatan mo'ljallangan vaqtga to'g'ri kelishini tasdiqlaydi. Buning uchun tizimni qayta yuklash yoki uning ishga tushishini kutish shart emas.

3. Timer’ni yoqish

sudo systemctl daemon-reload
sudo systemctl enable --now log-cleanup.timer

--now timer’ni darhol faollashtiradi va tizim yuklanganda uning avtomatik ishga tushishini ham ta’minlaydi. Bu yerda nima yoqilayotganiga e’tibor bering — log-cleanup.service emas, log-cleanup.timer. Service’ni bevosita yoqish shart emas, uni timer ishga tushiradi.

Holatni tekshirish

systemctl list-timers log-cleanup.timer
NEXT                        LEFT     LAST  PASSED  UNIT               ACTIVATES
Sat 2026-07-25 00:00:00 UTC 13h left n/a   n/a     log-cleanup.timer  log-cleanup.service
  • NEXT/LEFT — keyingi rejalashtirilgan ishga tushirish va unga qancha vaqt qolgani;
  • ACTIVATES — timer qaysi servisni ishga tushirishga sozlangani.

Bu systemd timer’larning cron’ga nisbatan aniq afzalligi: keyingi ishga tushish vaqtini crontab qatorini o'qib taxmin qilish yoki qayta yuklanishni kutish o'rniga to'g'ridan-to'g'ri tekshirish mumkin.

Chiqishni ko'rish: journalctl

journalctl -u log-cleanup.service --since today

cron’da chiqish odatda alohida sozlanishi kerak bo'lgan email yoki qo'lda tanlangan log fayl orqali kuzatiladi (cron muhiti va log'lari maqolasida ko'rib chiqilgan). systemd timer’da esa log-cleanup.service stdout yoki stderr ga yozgan hamma narsa hech qanday qo'shimcha sozlamasiz avtomatik ravishda journalctl ga tushadi.

Vazifa muvaffaqiyatli yoki xato bilan tugaganini bilish uchun:

systemctl status log-cleanup.service

Qo'lda ishga tushirish

Sinov uchun vazifani jadvalni kutmasdan darhol ishga tushirish:

sudo systemctl start log-cleanup.service

Bu timer’ga umuman tegmaydi — u shunchaki servisni bir marta ishga tushiradi. Shunday qilib, jadvalni vaqtincha o'zgartirmasdan asosiy buyruqni sinab ko'rish mumkin.

Interval timer’lar: OnBootSec va OnUnitActiveSec

OnCalendar= vazifani xuddi cron kabi aniq soat vaqtlariga bog'laydi. systemd shuningdek kalendarga emas, biror hodisaga nisbatan ishga tushadigan monotonic timer’larni ham taklif qiladi:

  • OnBootSec= — mashina yuklangandan keyingi belgilangan kechikish, masalan OnBootSec=15min ("har bir yuklanishdan 15 daqiqa keyin");
  • OnUnitActiveSec= — servis oxirgi marta faollashtirilgan vaqtdan boshlab o'lchanadigan belgilangan interval, masalan OnUnitActiveSec=10s.

Birinchi ishga tushirishning aniq boshlanish nuqtasi bo'lishi uchun ikkalasi odatda birga ishlatiladi:

[Timer]
OnBootSec=1min
OnUnitActiveSec=10s

Bu "birinchi marta yuklanishdan bir daqiqa keyin, so'ng har 10 soniyada" degani. Bu jadvalning umuman cron ekvivalenti yo'q — cron faqat aniq soat vaqtlarini ifodalay oladi va uning eng kichik aniqligi bir daqiqa. Har 10 soniyada yoki "shu host yuklangandan N daqiqa keyin" ishlashi kerak bo'lgan vazifa — cron asoslari dagi aniqlik haqidagi eslatma aynan shu yerga yo'naltirgan holat: timer’dan foydalaning, chunki cron buni ifodalay olmaydi.

Aniqlik va yuklamani taqsimlash: AccuracySec va RandomizedDelaySec

Standart holatda timer so'ralgan aniq soniyada ishga tushmaydi. AccuracySec= ning standart qiymati 1 daqiqa, shuning uchun systemd vazifani boshqa uyg'onishlar bilan birlashtirib, energiyani tejash uchun uni bir daqiqagacha kechiktirishi mumkin. Haqiqatan aniq soniyada ishga tushishi kerak bo'lgan vazifa buni alohida so'rashi kerak:

[Timer]
OnCalendar=*-*-* 03:00:00
AccuracySec=1s

RandomizedDelaySec= esa teskarisini qiladi va u cron’ga nisbatan haqiqiy production afzalligi. U har bir ishga tushirishga ko'rsatilgan qiymatgacha bo'lgan tasodifiy kechikish qo'shadi:

[Timer]
OnCalendar=daily
RandomizedDelaySec=1h

Bir xil daily backup’ni ishga tushiradigan yuzta serverdan iborat parkda oddiy 0 0 * * * cron qatori har bir hostni yarim tunda bir vaqtning o'zida backup manziliga murojaat qilishga majbur qiladi. Bu tarmoq va manzil uchun o'zimiz yaratgan "thundering herd" muammosi. RandomizedDelaySec=1h shu yuzta ishga tushirishni hostlar o'rtasida hech qanday kelishuvsiz yarim tundan keyingi bir soat davomida tasodifiy tarqatadi. cron bilan xuddi shunga erishish uchun har bir hostning jadvalini birma-bir qo'lda siljitib chiqishga to'g'ri keladi.

cron va systemd timer: qachon qaysi birini tanlash kerak

Mezon cron systemd timer
Sintaksis soddaligi Bitta qator, tez yoziladi Ikkita fayl, ko'proq shablon kod
Chiqish va xatolarni kuzatish Alohida sozlash kerak (email, log fayl) Avtomatik, journalctl orqali
O'tkazib yuborilgan vazifani qayta ishga tushirish (tizim o'chiq bo'lgan) Yo'q Ha, Persistent=true bilan
Keyingi ishga tushish vaqtini oldindan ko'rish Qiyin Oson, systemctl list-timers bilan
Boshqa systemd unit’ga bog'liqlik (masalan, tarmoq ko'tarilgandan keyin) Yo'q Ha, Wants=, After= bilan
Konteynerlashtirilgan yoki minimal muhitlar Ko'pincha allaqachon o'rnatilgan systemd talab qiladi (ba’zi konteynerlarda yo'q)
Tanishlik va hujjatlar Juda keng tarqalgan, deyarli hamma joyda tanish systemd’ga asoslangan tizimlarda keng tarqalgan, lekin cron kabi universal emas

Amalda ikkalasi ham to'g'ri javob bo'lishi mumkin. Mavjud, systemd’ga asoslangan serverda kuzatuvchanlik yoki bog'liqliklar kerak bo'lgan murakkabroq vazifalar uchun timer qulayroq. Keyinchalik boshqa turdagi tizimga ko'chirilishi mumkin bo'lgan oddiy, tez yoziladigan vazifalar uchun esa cron amaliy tanlov bo'lib qolaveradi.

Keng tarqalgan xatolar

  • .service ni yoqib, .timer ni unutish. Yolg'iz systemctl enable log-cleanup.service hech narsani jadval bo'yicha ishga tushirmaydi — Type=oneshot servis faqat uning timer’i ishga tushganda yoki qo'lda boshlanganda ishlaydi. Yoqilishi kerak bo'lgan unit — .timer fayli.
  • daemon-reload ni unutish. Unit faylni yaratgan yoki tahrirlagandan keyin systemctl daemon-reload o'tkazib yuborilsa, systemd unit haqidagi oldingi, eskirgan tasavvuri bilan ishlashda davom etadi.
  • Persistent=true ni cron xatti-harakati bilan chalkashtirish. Persistent=true faqat server o'chiq bo'lgan paytda o'tkazib yuborilgan ishga tushirishning o'rnini to'ldiradi. cron’da umuman bunga teng sozlama yo'q — tizim ishlamay turgan vaqtga rejalashtirilgan vazifa shunchaki o'tkazib yuboriladi va hech qachon bajarilmaydi.
  • Hech qachon ishga tushmaydigan, aniq xatosi ham yo'q timer. Uni tartib bilan diagnostika qiling: systemctl list-timers --all ni ishga tushiring. Agar timer umuman ro'yxatda bo'lmasa, u hech qachon yoqilmagan/ishga tushirilmagan (--now tushirib qoldirilgan yoki daemon-reload o'tkazib yuborilgan). Agar u ro'yxatda bo'lsa-yu, NEXT n/a ni ko'rsatsa, OnCalendar= ifodasi noto'g'ri — uni alohida systemd-analyze calendar '<expr>' bilan tekshiring. Agar jadval to'g'ri bo'lsa-yu, vazifa baribir noto'g'ri ishlasa, systemctl status <name>.timer unit yuklanishidagi xatolarni, journalctl -u <name>.service esa u oxirgi marta haqiqatan ishga tushganda nima bo'lganini ko'rsatadi.

Mashqlar

  1. echo/date ni ishga tushiradigan oddiy Type=oneshot servis yarating va uni har 5 daqiqada ishga tushadigan timer (OnCalendar=*:0/5) bilan juftlang.
  2. Keyingi rejalashtirilgan ishga tushirishni systemctl list-timers bilan kuzating, keyin chiqishni journalctl -u bilan tasdiqlang.
  3. Uchta turli OnCalendar= ifodasini systemd-analyze calendar bilan tekshiring va "Next elapse" natijasini o'zingiz kutgan natija bilan taqqoslang.
  4. Bir xil vazifani avval cron qatori, keyin systemd timer sifatida yozing va har biri qancha sozlashni talab qilganini taqqoslang.

Xulosa

systemd timer cron bilan bir xil maqsadga — buyruqni jadval bo'yicha ishga tushirishga — xizmat qiladi, lekin buni alohida .service/.timer fayllar jufti, journalctl orqali avtomatik log yozish va Persistent=true kabi qo'shimchalar orqali amalga oshiradi. Oddiy, tez yoziladigan vazifalar uchun cron amaliy bo'lib qolaveradi. Yaqinroq kuzatuv yoki unit bog'liqliklari kerak bo'lgan vazifalar uchun esa systemd timer ko'proq nazorat beradi.

Manbalar