Вопрос или проблема
Я хотел бы иметь возможность получать от systemd, сколько времени заняло последнее активация сервиса oneshot
. Я подумал о следующих вариантах, но они не совсем меня убедили:
-
Вычислить
InactiveEnterTimestamp - InactiveExitTimestamp
, например, прочитав их через интерфейс D-Bus на Python. Это имеет недостаток в том, что значение может быть непоследовательным (=отрицательным), пока сервис работает. -
Использовать вспомогательные скрипты в
ExecStartPre
иExecStartPost
, чтобы сохранить временную метку и вычислить прошедшее время, как только сервис завершится. -
Использовать обертку-скрипт вокруг исполняемого файла сервиса, которая сохранит прошедшее время где-то на файловой системе, как только основной исполняемый файл завершится.
-
Использовать вспомогательный скрипт в
ExecStartPost
, который сохранит значение, вычисленное в пункте #1.
Я предпочел бы #4, если это возможно, а затем #3, если нет. Что бы вы предложили? Есть ли лучший способ сделать это?
Контекст: Я запускаю Tiny Tiny RSS, у которого есть скрипт обновления ленты, который я запускаю через регулярные интервалы с помощью таймера systemd. Я также запускаю Isync таким же образом, чтобы резервировать содержимое моего почтового ящика Gmail. Моя конечная цель — иметь возможность контролировать, сколько времени занимает каждое включение сервиса, и получать уведомления, если это занимает слишком много времени или не запускалось долго.
Редактирование: Мой файл сервиса выглядит так:
[Unit]
Description=Обновление лент Tiny Tiny RSS
After=network.target mysqld.service postgresql.service
[Service]
Type=oneshot
ExecStart=/usr/bin/php /usr/share/webapps/tt-rss/update.php --feeds
User=ttrss
StandardOutput=syslog
StandardError=syslog
А вот и таймер:
[Unit]
Description=Таймер обновления лент Tiny Tiny RSS
[Timer]
OnBootSec=1s
OnUnitInactiveSec=120s
Persistent=true
Unit=tt-rss.service
[Install]
WantedBy=timers.target
Вычислить InactiveEnterTimestamp – InactiveExitTimestamp
Время активации (в секундах) — это результат:
(ActiveEnterTimestampMonotonic - InactiveExitTimestampMonotonic) / 1e6
Смотрите функцию analyze_plot
в файле analyze.c для получения деталей.
Но в вашем юните должно быть RemainAfterExit=yes
, чтобы получить ActiveEnterTimestampMonotonic
.
Вы можете вычислить ExecMainExitTimestampMonotonic - ExecMainStartTimestampMonotonic
в ExecStartPost
без RemainAfterExit
.
например, прочитав их через интерфейс D-Bus на Python.
Вы можете использовать systemctl
, чтобы извлечь эти значения:
$ systemctl show -p InactiveExitTimestampMonotonic -p ActiveEnterTimestampMonotonic unit
InactiveExitTimestampMonotonic=44364325621
ActiveEnterTimestampMonotonic=44369331083
Согласно Обещанию стабильности интерфейса:
Стабильные интерфейсы:
...
Командная строка интерфейсы systemctl, loginctl, journalctl.
Мы гарантируем, что скрипты, вызывающие эти команды, будут продолжать
работать с будущими версиями systemd. Обратите внимание, что выходные данные,
генерируемые этими командами, обычно не включены в обещание,
если это не задокументировано в руководстве. Пример: выходные данные
"systemctl status" не стабильны, но выходные данные "systemctl show" стабильны,
поскольку первый предназначен для чтения человеком, а второй -
для чтения компьютером, и это задокументировано в руководстве.
Моя конечная цель — иметь возможность контролировать, сколько времени занимает каждое включение сервиса, и получать уведомления, если это занимает слишком много времени
Вы можете установить TimeoutStartSec и OnFailure:
TimeoutStartSec=
Настраивает время ожидания для запуска. Если служба-демон не
подтверждает завершение запуска в заданное время, служба будет считаться
неудачной и будет остановлена снова.
OnFailure=
Список из одного или нескольких юнитов, которые активируются, когда
этот юнит входит в состояние "неудача".
или не запускался долго
Вы можете извлечь время последнего успешного запуска из журнала:
journalctl -u ваш-сервис MESSAGE='Started ваш-сервис.service.'
Но вам следует включить постоянное хранение журналов сообщений.
Ответ или решение
Для мониторинга времени активации сервиса oneshot
в systemd
, вы можете использовать несколько подходов, однако одним из более эффективных способов является использование параметров, связанных с временными метками, а также настройки вашего сервиса.
1. Использование временных меток
Одним из возможных решений является расчет времени активации на основании временных меток, которые предоставляет systemd
. Вам понадобятся следующие параметры:
InactiveExitTimestampMonotonic
ActiveEnterTimestampMonotonic
Эти значения можно получить с помощью команды:
systemctl show -p InactiveExitTimestampMonotonic -p ActiveEnterTimestampMonotonic имя_сервиса
Тем не менее, чтобы получить доступ к ActiveEnterTimestampMonotonic
, ваш единичный файл сервиса должен содержать следующее:
[Service]
RemainAfterExit=yes
Тогда вы можете рассчитать время активации следующим образом:
время_активации = (ActiveEnterTimestampMonotonic - InactiveExitTimestampMonotonic) / 1e6
2. Использование ExecStartPost
Вы можете реализовать логику расчета времени активации непосредственно в вашем ExecStartPost
. Это позволяет вам извлечь временные метки, хранящиеся в systemd
, и вычислить разницу. Примерный скрипт может выглядеть так:
#!/bin/bash
inactive_exit=$(systemctl show -p InactiveExitTimestampMonotonic имя_сервиса | cut -d= -f2)
active_enter=$(systemctl show -p ActiveEnterTimestampMonotonic имя_сервиса | cut -d= -f2)
activation_time=$((active_enter - inactive_exit))
echo $activation_time > /path/to/activation_time.log
Добавьте этот скрипт в ExecStartPost
вашего сервиса:
ExecStartPost=/путь/к/вашему/скрипту.sh
3. Установка таймаутов и уведомлений
Для того чтобы вы могли реагировать на слишком долгую работу сервиса или если он не запускается долгое время, вы можете использовать параметры TimeoutStartSec
и OnFailure
. Например:
[Service]
TimeoutStartSec=30
OnFailure=your-failure-handler.service
Это позволит вам настроить, что должно произойти, если запуск вашего сервиса превысит заданный тайм-аут.
4. Мониторинг состояния сервиса
Чтобы отслеживать, когда ваш сервис в последний раз выполнялся успешно, вы можете использовать journalctl
. Например:
journalctl -u имя_сервиса MESSAGE='Started имя_сервиса.service.'
Не забудьте включить сохранение логов для обеспечения постоянного доступа к журналам.
Заключение
Изложенные методы помогут вам эффективно мониторить время активации ваших oneshot
сервисов и обеспечивать их стабильность. Выбор между использованием временных меток и скриптов — это вопрос предпочтений, но подход с ExecStartPost
(вариант #4) позволяет более целостно интегрировать логику прямо в конфигурацию сервиса.