Systemd-timers
как способ запускать своих скриптов в нужное время. Можно конечно пользоваться старым
добрым cron
, но таймеры гибче позволяют настроить время и периодичность запуска.
Почему
Для периодического запуска скриптов есть cron
, но у него есть несколько проблем, которые могут мешать:
- крон может быть только периодическим, не получится полноценно описать “календарный” или событийный вариант запуска ( разве что внутри скрипта проверять дату-вермя);
- крон срабатывает раз в минуту, то есть минимальный период времени - 1 минута (есть всякого уровня “хаки”, вроде вызова
с предварительным
sleep 15
, но это хаки); - крон просто запускает скрипт, as is (проверка того что скрипт еще работает, все то что можно сделать в декларативной форме в unit-файле systemd - нужно делать самому);
- крон скрипты не умеют в “зависимости”;
- крон скрипты обычно хранятся внутри
/etc
, а не все могут туда писать.
Может еще есть какие мелочи, но это те ограничения с которыми приходилось сталкиваться. Для таймеров же для меня есть два основных недостатка:
- необходимо два разных файла (unit - что выполнить, timer - когда выполнить), за исключением временных задач;
- нет отправки email уведомлений (
EMAILTO
изcron
), тут нужно подумать об этом самому.
Для меня минусы не столь значительны и перекрываются плюсами. Поэтому приступим.
Хранение таймеров
Итак, что бы создать timer - нужен unit файл. Как он создается, какой он может быть и тд оставим за рамками этого
текста. Для нашего пример это будет task.service
. Таймеры по месту хранения будут двух типов.
Проверить таймеры в системе
Начнем с того, что таймеров есть два списка: системный и пользовательский. Вызов для работы с ними отличается
использованием или не использованием ключа --user
.
Для просмотра всех таймеров в системе можно воспользоваться командой (для всех таймеров текущего пользователя добавить
ключ --user
):
|
|
В полученной таблице будут следующие столбцы:
NEXT
- дата и время следующего запуска таймера;LEFT
- время до следующего запуска таймера;LAST
- дата и время последнего запуска таймера;PASSED
- время с последнего запуска таймера;UNIT
- имяtimer
-файла;ACTIVATES
- имяunit
-файла для запуска.
По умолчанию имя timer
и unit
файлов должны быть одинаковыми (за исключением этих суффиксов), но есть возможность
указать кастомное имя timer
-файла и привязать его к стандартному unit
-файлу. Пример такой записи:
|
|
Где искать файлы
Все таймеры хранятся в 3 основных местах:
/lib/systemd/system
- “встроенные” таймеры;/etc/systemd/system
- кастомные системные таймеры;~/.config/systemd/user
- кастомные таймеры пользователя.
Типы таймеров по времени запуска
По времени запуска есть два типа таймеров:
Realtime timers
- таймеры реального времени привязанные к датам;Monotonic timers
- монотонные таймеры привязанные к периодам времени.
При работе с таймерами нужно иметь в виду, что со временем в системе могут происходить разного рода особенности, например:
- сон компьютера, при этом время не останавливается;
- может поменяться временная зона;
- само время может “ускорится” или “замедлиться” для синхронизации.
Таймеры реального времени
В таймере реального времени главный параметр - OnCalendar
внутри блока [Timer]
. Параметры может быть:
OnCalendar=daily
- ежедневный запуск (в 00:00:00);OnCalendar=monday *-10-* 17:00
- каждый понедельник октября в 17 часов;OnCalendar=08:00:00
- каждый день в 8 утра.
Полное описание формата можно посмотреть в systemd.time(7). Для локального тестирования можно воспользоваться командой:
|
|
Ответ получается такого вида:
|
|
Так же для такого типа таймера есть несколько вспомогательных параметров (основные для использования мной):
Persistent
- значениеtrue
илиfalse
, при отсутствии времени предыдущего запуска сразу запускает таймер;RandomizedDelaySec
- позволяет задать “промежуток” времени в который можно выполнить таймер, если на одно и то же время ставится много таймеров, то это позволяет “размазать” их запуск по этому промежутку;FixedRandomDelay
- “запоминает” промежуток для таймера с параметром выше;AccuracySec
- это попытка “собрать похожие по времени таймеры”, что не “будить” процессор лишний раз. По умолчанию значение здесь 1 минута, для рандомизированно запущенных таймеров лучше всего проставить значение1us
.
Монотонные таймеры
Основные параметры монотонных таймеров:
OnActiveSec
- период времени с момента активации таймера;OnBootSec
- время после загрузки (для контейнеров этот параметр будет эквивалентомOnStartupSec
), не работает для пользовательских таймеров;OnStartupSec
- время со старта сервис-менеджера, для системных таймеров очень близок кOnBootSec
, для контейнеров - это время запуска контейнера, для пользователя - время входа в систему;OnUnitActiveSec
- определяет промежуток времени с последней активации таймера, в который таймер должен быть повторно активирован (если за сеанс нужно выполнять задачу несколько раз);OnUnitInactiveSec
- то же самое что выше, но учитывает время деактивации.
Дополнительные же параметры тут такие:
OnClockChange
- выполнить таймер при смещении времени (синхронизация, установка времени руками);OnTimezoneChange
- выполнить таймер при изменении часового пояса.
Пример из моей жизни
Подгрузка базы паролей pass
У pass, который используется для хранения паролей, есть возможность хранить БД под
версионированием в git. Но стандартные механизмы умеют только автоматом пушить изменения. Так как у меня есть несколько
машин, нужно время от времени эти изменения на каждую из них пулить. Для этого был написан простой скрипт и запущен
таймер по нему, который через минуту после включения пулит свежую БД для pass
, и далее проверяет обновления каждые 8
часов.
|
|
Отложенный старт Docker
Появилась необходимость отсрочить старт сервиса Docker (и всех контейнеров). Для этого всего лишь убрал сервис докера из автозагрузки:
|
|
И добавил таймер для запуска Docker через 5 минут после загрузки системы.
|
|
Таймер для certbot идущий в комплекте с пакетом
Запускается каждый день два раза в сутки в произвольное время в пределах от 00:00 до 12:00 и от 12:00 до 00:00.
|
|