systemd (Русский)/Timers (Русский)
Таймеры — файлы юнитов systemd, имя которых имеет суффикс .timer; они позволяют контролировать файлы .service или события. Таймеры могут использоваться в качестве замены cron (смотрите #В качестве замены cron). Таймеры имеют встроенную поддержку календарных и регулярных событий и могут запускаться в асинхронном режиме.
Юниты таймера
Таймеры systemd — файлы юнитов с суффиксом .timer. Они хранятся в тех же каталогах, что и другие файлы настроек юнитов, но включают в себя раздел [Timer]
, который определяет, как и когда таймер запускается. Существует два типа таймеров:
-
Таймеры реального времени (также известные как настенные часы) запускаются в зависимости от событий календаря (как cronjobs). Для определения таких таймеров используется опция
OnCalendar=
. -
Монотонные таймеры активируются после определенного промежутка времени по отношению к той или иной отправной точке. Они не сработают, если компьютер находится в режиме ожидания или выключен. Есть несколько различных монотонных таймеров, но все они имеют вид:
OnTypeSec=
. Обычно монотонные таймеры включают в себяOnBootSec
иOnUnitActiveSec
.
Подробнее см. systemd.timer(5). Синтаксис аргументов для календарных событий и временных промежутков можно найти в systemd.time(7).
timers.target
, к которой можно привязать таймеры, запускаемые сразу после загрузки системы (подробнее см. systemd.special(7)). Чтобы ею воспользоваться, укажите параметр WantedBy=timers.target
в разделе [Install]
файла таймера, после чего включите юнит.Юнит службы
Каждому файлу .timer соответствует файл .service (например, foo.timer
и foo.service
). .timer запускается и контролирует .service. .service не требует раздела [Install]
, так как последний присутствует в юните timer, который уже включен. Если необходимо, то можно контролировать юниты с разным названием, используя опцию Unit=
в таймере в разделе [Timer]
.
Управление
Для того, чтобы использовать юнит-timer, включите и запустите его, как любой другой юнит (не забудьте добавить суффикс .timer). Для того, чтобы увидеть все запущенные таймеры, выполните:
$ systemctl list-timers
NEXT LEFT LAST PASSED UNIT ACTIVATES Thu 2014-07-10 19:37:03 CEST 11h left Wed 2014-07-09 19:37:03 CEST 12h ago systemd-tmpfiles-clean.timer systemd-tmpfiles-clean.service Fri 2014-07-11 00:00:00 CEST 15h left Thu 2014-07-10 00:00:13 CEST 8h ago logrotate.timer logrotate.service
- Чтобы увидеть все таймеры (в том числе и неактивные), используйте
systemctl list-timers --all
. - Статус службы, запускаемой посредством таймера, вероятно, будет неактивным, если, конечно, она не была запущена непосредственно перед проверкой статуса.
- Если таймер рассинхронизировался, то может помочь удаление соответствующих файлов
stamp-*
в/var/lib/systemd/timers
(или~/.local/share/systemd/
). Это файлы нулевого размера, которые отмечают последнее время запуска таймера. Если данные файлы отсутствуют, то они будут перестроены при следующем запуске соответствующего таймера.
Примеры
Запуск службы может быть запланирован по таймеру. В последующих примерах назначается запуск foo.service
в соответствии с таймером foo.timer
.
Монотонный таймер
Таймер, который запустится через 15 минут после загрузки, а затем снова будет запускаться каждую неделю во время работы системы.
/etc/systemd/system/foo.timer
[Unit] Description=Run foo weekly and on boot [Timer] OnBootSec=15min OnUnitActiveSec=1w [Install] WantedBy=timers.target
Таймер реального времени
Таймер, который будет запускаться один раз в неделю (в 12:00 в понедельник). При активации он сразу же запустит службу, если отсутствует последнее время запуска (опция Persistent=true
), например, в связи с отключением системы:
/etc/systemd/system/foo.timer
[Unit] Description=Run foo weekly [Timer] OnCalendar=weekly Persistent=true [Install] WantedBy=timers.target
Если требуется указать более точную дату и время, используйте следующий формат:
ДеньНедели Год-Месяц-День Часы:Минуты:Секунды
Звездочка может быть использована, чтобы указать все значения, а запятые, в свою очередь, для перечисления возможных значений. Используйте ..
, чтобы выделить какой-то конкретный промежуток. В следующем примере служба запускается в первые четыре дня каждого месяца в полдень, но только если день является понедельником или вторником.
OnCalendar=Mon,Tue *-*-01..04 12:00:00
Запуск службы в первую субботу каждого месяца:
OnCalendar=Sat *-*-1..7 18:00:00
По крайней мере один день должен быть указан при использовании ДеньНедели
. Таймер, который будет запускаться каждый день в 4 утра:
OnCalendar=*-*-* 4:00:00
Если необходимо запускать службу в разное время, то можно указать параметр OnCalendar
несколько раз. В примере ниже служба запускается в 22:30 по рабочим дням и в 20:00 по выходным:
OnCalendar=Mon..Fri 22:30 OnCalendar=Sat,Sun 20:00
Подробнее см. systemd.time(7).
- Указатели времени
OnCalendar
могут быть протестированы для того, чтобы проверить их правильность и вычислить следующее время срабатывания условия. Например,systemd-analyze calendar weekly
илиsystemd-analyze calendar "Mon,Tue *-*-01..04 12:00:00"
. - Команда
faketime
полезна для тестирования с командой выше. Установите пакет libfaketime. - Специальные выражения событий, такие как
daily
иweekly
, относятся к конкретному времени начала и, таким образом, все таймеры, использующие эти выражения, запустятся одновременно. Таймеры, использующие специальные выражения, могут негативно сказаться на производительности системы, если сервисы, запускаемые таймерами, являются ресурсозатратными. ОпцияRandomizedDelaySec
в разделе[Timer]
помогает избежать подобных проблем посредством случайного выбора времени запуска каждого из таймеров. Смотрите systemd.timer(5). - Добавьте опцию
AccuracySec=1us
в раздел[Timer]
, чтобы не использовать значение погрешности 1m, установленное по умолчанию. См. также systemd.timer(5).
Временные юниты .timer
Можно использовать systemd-run
для создания временных юнитов .timer. То есть можно назначить запуск определённой команды в нужное время, не имея соответствующего файла службы. Например, следующая команда создаст файл через 30 секунд:
# systemd-run --on-active=30 /bin/touch /tmp/foo
Кроме того, можно указать предварительно существующий файл сервиса, при этом не имея файла таймера. Например, запустим юнит, который называется некоторыйюнит.service
, через 12.5 часов:
# systemd-run --on-active="12h 30m" --unit некоторыйюнит.service
Смотрите systemd-run(1) для получения дополнительной информации и примеров.
В качестве замены cron
Несмотря на то, что cron, возможно, самый известный планировщик задач, таймеры systemd могут выступать в качестве альтернативы.
Преимущества
Основные преимущества использования таймеров приходят от каждой задачи, которая имеет собственную службу systemd. Вот некоторые из этих преимуществ:
- Задачи могут быть легко запущены независимо от их таймеров. Это упрощает отладку.
- Каждая задача может быть настроена для работы в определенной среде (смотрите systemd.exec(5)).
- Задачи могут быть присоединены к cgroups.
- Задачи могут быть настроены в зависимости от других юнитов systemd.
- Задачи регистрируются в журнале systemd для легкости отладки.
Предостережения
Некоторые вещи, которые легко сделать посредством cron, трудно сделать только юнитами таймера.
- Создание: чтобы настроить задачу, запускаемую в определенное время, при помощи systemd, вам нужно создать два файла и использовать команды
systemctl
. Сравните это с добавлением одной строчки в crontab. - Электронная почта: отсутствие встроенного эквивалента cron
MAILTO
для отправки писем при сбое. В следующем разделе приведен пример создания эквивалента с использованиемOnFailure=
.
Также обратите внимание, что пользовательские юниты-таймеры будут запускаться только тогда, когда активен сеанс соответствующего пользователя. Тем не менее, долговременные службы могут запускаться при загрузке системы даже если пользователь не выполнил вход.
MAILTO
Вы можете настроить systemd для отправки электронной почты при сбое юнита - так же, как Cron делает с MAILTO
. Прежде всего, нужно два файла: исполняемый для посылки почты и .service для запуска первого. В следующем примере, исполняемый файл - скрипт, использующий sendmail
, который можно найти в пакетах, предоставляющих smtp-forwarder
.:
/usr/local/bin/systemd-email
#!/bin/sh /usr/bin/sendmail -t <<ERRMAIL To: $1 From: systemd <root@$HOSTNAME> Subject: $2 Content-Transfer-Encoding: 8bit Content-Type: text/plain; charset=UTF-8 $(systemctl status --full "$2") ERRMAIL
Исполняемый файл, видимо, должен получать минимум два аргумента, полученных сценарием: адрес для отправки и файл юнита для получения статуса. Файл .service, который мы создадим, будет передавать эти аргументы:
/etc/systemd/system/status_email_user@.service
[Unit] Description=status email for %i to user [Service] Type=oneshot ExecStart=/usr/local/bin/systemd-email address %i User=nobody Group=systemd-journal
Здесь user
— получатель почты, а address
— адрес электронной почты пользователя. Хотя получать "захардкожен", файл юнита для отчёта передается как параметр экзепляра, поэтому данная служба может посылать электронные письма множеству юнитов. Запустите status_email_user@dbus.service
, чтобы убедиться, что вы можете получать почту.
Затем просто отредактируйте службу, от которой вы хотите получать почту и добавьте OnFailure=status_email_user@%n.service
в раздел [Unit]
. %n
передает имя юнита в шаблон.
- Если вы настроили sSMTP в соответствии с sSMTP#Security, то пользователь
nobody
не будет иметь доступа к/etc/ssmtp/ssmtp.conf
и командаsystemctl start status_email_user@dbus.service
не сработает. Одним из решений является использованиеroot
-пользователя в юнитеstatus_email_user@.service
. - Если вы попробуете использовать
mail -s somelogs address
в почтовом скрипте,mail
создаст свой форк и systemd убьет процесс посылки почты, когда увидит, что скрипт завершился. Можно сделать так, чтобы почтовый процесс не создавал своих форков путем выполненияmail -Ssendwait -s somelogs address
.
Использование crontab
Некоторые из предостережений можно обойти путем установки пакета, который анализирует crontab, а затем настраивает таймеры на его основе. systemd-cron-nextAUR[ссылка недействительна: package not found] и systemd-cronAUR — два таких пакета. Они могут предоставлять недостающую функцию MAILTO
.
Если вам нравится crontabs только потому, что он предоставляет единый вид для всех запланированных задач, systemctl
делает тоже самое. Смотрите #Управление
Смотрите также
- systemd.timer(5)
- Fedora:Features/SystemdCalendarTimers
- Gentoo:Systemd#Timer services
- systemd-cron-next — утилита для создания таймеров/служб из файлов crontab и anacrontab
- https://github.com/systemd-cron/systemd-cron-next || systemd-cron-nextAUR[ссылка недействительна: package not found]
- systemd-cron — предоставляет юнитам systemd запускать скрипты cron; используя systemd-crontab-generator для конвертации crontab'ов