systemd (Русский)/Timers (Русский) - ArchWiki

Jump to content
< Systemd (Русский)

Ссылки по теме

- systemd (Русский)
- systemd/Пользователь
- systemd FAQ
- cron (Русский)

Состояние перевода: На этой странице представлен перевод статьи systemd/Timers. Дата последней синхронизации: 12 июля 2021. Вы можете помочь синхронизировать перевод, если в английской версии произошли изменения.

Таймеры — файлы юнитов systemd, имя которых имеет суффикс .timer; они позволяют контролировать файлы .service или события. Таймеры могут использоваться в качестве замены cron (смотрите #В качестве замены cron). Таймеры имеют встроенную поддержку календарных и регулярных событий и могут запускаться в асинхронном режиме.

## Юниты таймера

Таймеры systemd — файлы юнитов с суффиксом .timer. Они хранятся в тех же каталогах, что и другие файлы настроек юнитов, но включают в себя раздел `[Timer]`, который определяет, как и когда таймер запускается. Существует два типа таймеров:

- Таймеры реального времени (также известные как настенные часы) запускаются в зависимости от событий календаря (как cronjobs). Для определения таких таймеров используется опция `OnCalendar=`.
- Монотонные таймеры активируются после определенного промежутка времени по отношению к той или иной отправной точке. Они не сработают, если компьютер находится в режиме ожидания или выключен. Есть несколько различных монотонных таймеров, но все они имеют вид: `OnTypeSec=`. Обычно монотонные таймеры включают в себя `OnBootSec` и `OnUnitActiveSec`.

Подробнее см. systemd.timer(5). Синтаксис аргументов для календарных событий и временных промежутков можно найти в systemd.time(7).

Примечание: В systemd предусмотрена цель `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 и 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

- systemd-cron — предоставляет юнитам systemd запускать скрипты cron; используя systemd-crontab-generator для конвертации crontab'ов

  https://github.com/systemd-cron/systemd-cron || systemd-cronAUR

- Systemd Timers for Scheduling Tasks

Category:

- System administration (Русский)