Таймеры systemd вместо crond: различия между версиями
Дым (обсуждение | вклад) |
Дым (обсуждение | вклад) |
||
Строка 52: | Строка 52: | ||
|} | |} | ||
Само собой, «doit» что в именах, что в шаблоне таймера и периодически запускаемых сервисах можно заменить на «do», «run», «cron», «launch» или что угодно иное. | Само собой, «doit» что в именах, что в шаблоне таймера и периодически запускаемых сервисах можно заменить на «do», «run», «cron», «launch» или что угодно иное. | ||
===2) Включить и запустить периодические таймеры=== | ===2) Включить и запустить периодические таймеры=== | ||
# systemctl enable --now doit@{minute,hour,dai,week,month,quarter,semi-annual,year}ly.timer | # systemctl enable --now doit@{minute,hour,dai,week,month,quarter,semi-annual,year}ly.timer | ||
==Или оба шага одним скриптом== | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
!doit.make | |||
|- | |||
|<source lang="ифыр"> | |||
#!/bin/sh | |||
SVC=/lib/systemd/system/doit@ | |||
target="[Unit] | |||
Description = %i timer target | |||
StopWhenUnneeded = yes" | |||
timer="[Unit] | |||
Description = %i timer | |||
[Timer] | |||
OnCalendar = %i | |||
Persistent = true | |||
Unit = doit@%i.target | |||
[Install] | |||
WantedBy = timers.target" | |||
for TYPE in timer target; do | |||
TGT=$SVC.$TYPE | |||
[ -f $TGT -a ! -s $TGT ] || echo "${!TYPE}" >$TGT | |||
done | |||
systemctl enable --now doit@{minute,hour,dai,week,month,quarter,semi-annual,year}ly.timer | |||
</source> | |||
|} | |||
===3) Создать сервисы, требующие периодического исполнения=== | ===3) Создать сервисы, требующие периодического исполнения=== | ||
Пример найден на просторах интернетов, нужную периодичность (можно сразу для нескольких интервалов) указывать через секцию '''[Install]''': | Пример найден на просторах интернетов, нужную периодичность (можно сразу для нескольких интервалов) указывать через секцию '''[Install]''': |
Версия от 08:49, 7 августа 2024
Предмет статьи
Речь о задачах, которые следует исполнять периодически, без указания сложных конструкций из даты:времени/периодичности (сиречь, о том, чем занимаются скрипты из /etc/cron.***ly/, плюс не охваченные ими ежеминутные, ежеквартальные и ежесеместровые запуски).
Варианты
В части руководств встречаются рекомендации «пилить» таймеры под каждый отдельный юнит, существуют и генераторы таймеров на основе crontab — проекты некоторых можно глянуть здесь. Но мне они показались несколько выморочными, чересчур навороченными — ведь всё необходимое уже наличествует в systemd, и следует признать: находились таки примеры с таймерами/таргетами на отдельные периоды — часы/дни/недели и т.п.
Но посредством шаблонов можно сделать проще.
Реализация
1) Создать пару шаблонов
Для периодических таймеров:
развернуть/lib/systemd/system/doit@.timer |
---|
Для их «целей»:
развернуть/lib/systemd/system/doit@.target |
---|
doit здесь — это про:
развернуть«делать еже…» |
---|
Само собой, «doit» что в именах, что в шаблоне таймера и периодически запускаемых сервисах можно заменить на «do», «run», «cron», «launch» или что угодно иное.
2) Включить и запустить периодические таймеры
# systemctl enable --now doit@{minute,hour,dai,week,month,quarter,semi-annual,year}ly.timer
Или оба шага одним скриптом
развернутьdoit.make |
---|
3) Создать сервисы, требующие периодического исполнения
Пример найден на просторах интернетов, нужную периодичность (можно сразу для нескольких интервалов) указывать через секцию [Install]:
развернуть/lib/systemd/system/logrotate.service |
---|
4) И, наконец, включить их
# systemctl enable <список таких сервисов>
…напоследок проверив, что юниты нужных сервисов активированы:
развернуть# ls /etc/systemd/system/doit@*ly.target.wants
|
---|
…и удостоверившись, что всё заработало:
развернуть# systemctl list-timers
|
---|
Можно выключить крон:
# systemctl disable --now crond
Не важно, что реально работает только часть таймеров, а остальные — пустышки: лишние можно отключить либо рассматривать их как заготовки вроде пустых каталогов из /etc/cron.<…>ly/
.
Другие примеры
Само собой, для сложных конструкций взамен кронтабов из /etc/cron.d/
придётся создавать отдельные таймеры, которые, однако, справятся и там, где крон нужно подпирать костылём — вроде чистки ZFS по вторым воскресеньям ежемесячно:
24 0 8-14 * * root [ $(date +\%w) -eq 0 ] && [ -x /usr/lib/zfs-linux/scrub ] && /usr/lib/zfs-linux/scrub
или проверки программного RAID-массива:
57 0 * * 0 root [ $(date +\%d) -le 7 ] && [ -x /usr/share/mdadm/checkarray ] && /usr/share/mdadm/checkarray --cron --all --idle --quiet
Из чего видно, что в кроновском «моменте запуска» нельзя сочетать диапазон чисел месяца с днями недели, так что без скрипта никак. Вот и второй пример его автор в вольном переводе комментирует так:
Запускать задачу следует по воскресеньям, но не позже 7 числа — то есть, лишь в первое воскресенье каждого месяца, в каковой ситуации кронтаб беспомощен, так что приходится костылить хак.
А вот пример таймера для запуска в последнее воскресенье каждого месяца без скриптов:
развернуть/lib/systemd/system/last-sunday.timer |
---|
…и его таргета:
развернуть/lib/systemd/system/last-sunday.target |
---|
Остаётся создать сервис-юниты с соответствующими строками запуска:
развернуть/lib/systemd/system/some-name.service |
---|
Всё это может выглядеть громоздко, однако:
- таймер с таргетом создаются однократно, а для каких-то сервисов таргет не обязателен — достаточно, чтоб имена таймера и сервиса совпадали;
- юниты нужны лишь под отдельные службы;
- всегда можно посмотреть результат отработки таких служб через
journalctl -u <service>.service
.
Таймеры рабочего времени
Недавно нашёл пару статей на хабре, куда не приняли ту, что вы сейчас читаете. :) Там во многом подробнее, но ни одного примера интервалов подобного рода.
Например, для выполнения задачи каждые полчаса с утра до вечера, подходит такой:
OnCalendar = 08..18:15,45:00
А для более длительных промежутков — например, двухчасовых — можно сделать так:
OnCalendar = 9..17/2:05:00
Ещё из этих интервалов можно исключить выходные дни, а если чуток извернуться — то и праздники. :)