Определите один конечный фрагмент работы
Представьте персональный инструмент, который пересобирает небольшую ежедневную сводку из своих существующих записей. Задание читает ограниченный набор данных, подготавливает одну заменяющую сводку и завершается. Это не веб-сервер, и он не должен продолжать работу между запланированными запусками. Запишите входные данные, назначение, ожидаемую длительность и то, что считается успехом, перед добавлением таймера.
Пример предполагает хост Linux с systemd и util-linux flock, доступ администратора и существующую непривилегированную учётную запись и группу с именем fieldjob. Его проверенный скрипт задания находится в /opt/field-jobs/build-summary и запускается на переднем плане. Администратор владеет этим скриптом; учётная запись задания может читать и выполнять его, но не может переписывать его код. Проверьте пути исполняемых файлов в вашем дистрибутиве. Это шаблоны, а не установленный сервис планирования OffVPS.
Скрипт должен сообщать о сбое с ненулевым статусом выхода. Для заменяющих файлов разработайте его так, чтобы он подготавливал и проверял временный результат перед публикацией. Для работы с базой данных используйте механизм транзакций или дедупликации базы данных. Одна блокировка не может сделать частично завершённую задачу безопасной для повторения.
Выберите часовой пояс и политику пропущенных запусков
Наша сводка полезна раз в день в 02:15 UTC. Используйте явный часовой пояс, чтобы локальный часовой пояс машины не был невидимой зависимостью. UTC избегает сезонных изменений часов в этом примере; бизнес-задача, привязанная к местному гражданскому времени, требует именованного часового пояса и проверки его поведения при переходе на летнее время. ссылка на время в systemd описывает календарные выражения.
Сохраните этот шаблон как /etc/systemd/system/field-summary.timer на предполагаемом VPS после проверки имён:
[Unit]
Description=Daily personal-tool summary
[Timer]
OnCalendar=*-*-* 02:15:00 UTC
Persistent=true
Unit=field-summary.service
[Install]
WantedBy=timers.target
Persistent=true запрашивает активацию догона после периода неактивности, если календарное событие было пропущено. Он не воспроизводит отдельный запуск для каждого пропущенного дня. Таймер также не запускает другой экземпляр той же службы, пока эта служба активна. Эти модели поведения и точность планирования описаны в справочнике по таймерам. Решите, полезна ли поздняя сводка, перед включением догона.
Задайте служебного пользователя, каталог состояния и блокировку
Соответствующий /etc/systemd/system/field-summary.service описывает работу:
[Unit]
Description=Build the personal-tool summary
[Service]
Type=oneshot
User=fieldjob
Group=fieldjob
WorkingDirectory=/opt/field-jobs
StateDirectory=field-summary
StateDirectoryMode=0700
UMask=0077
ExecStart=/usr/bin/flock --nonblock --conflict-exit-code 75 /var/lib/field-summary/job.lock /opt/field-jobs/build-summary
TimeoutStartSec=5min
StandardOutput=journal
StandardError=journal
Type=oneshot подходит для команды, которая завершается; явный тайм-аут запуска ограничивает этот пример. Не добавляйте RemainAfterExit=yes к службе, которая должна становиться неактивной после каждого запуска. См. семантику служб systemd. Установите тайм-аут исходя из рабочей нагрузки и сделайте прерывание безопасным, а не предполагайте, что пять минут подходят для каждого задания.
Для этой системной службы StateDirectory создаёт именованный каталог в /var/lib с владением службы. Рабочий каталог, пользователь, разрешения и назначения вывода указаны явно; скрипт должен использовать абсолютные пути для своих инструментов и данных. Правила окружения и каталогов описаны в справочнике systemd по выполнению. Не помещайте секретные значения в аргументы командной строки и не записывайте их в журнал.
Неблокирующая flock обёртка завершается с кодом 75, когда другой кооперирующийся вызов удерживает эту блокировку. Мы намеренно оставляем это видимым сбоем, требующим проверки, а не считаем пропущенную сводку выполненной работой. Все ручные вызовы должны использовать одну и ту же обёртку и путь блокировки. Не удаляйте файл блокировки, чтобы освободить работающее задание: новый файл может создать отдельную блокировку. Это шаблон локальной файловой системы, а не распределённая блокировка между экземплярами VPS. См. руководство flock от upstream.
Проверьте файлы, затем попробуйте один контролируемый запуск
Используйте одноразовый набор данных с отключённой исходящей почтой, платежами и другими побочными эффектами для первого запуска. Перед активацией проверьте разобранное расписание и файлы юнитов на этом тестовом хосте:
systemd-analyze calendar '*-*-* 02:15:00 UTC'
systemd-analyze verify /etc/systemd/system/field-summary.service /etc/systemd/system/field-summary.timer
Эти проверки могут выявить ошибки в юнитах и расписании; они не могут установить, что ваш скрипт создаёт корректную сводку. справочник systemd-analyze объясняет их область применения. После исправления ошибок загрузите проверенные файлы и явно запустите тестовое задание:
sudo systemctl daemon-reload &&
sudo systemctl start field-summary.service
systemctl status field-summary.service --no-pager
sudo journalctl -u field-summary.service --since "10 minutes ago" --no-pager
Ожидайте конечный успешный вызов и проверенный выходной артефакт; успешный oneshot впоследствии может отображаться как inactive. Изучите сам результат, включая поведение при пустом вводе. Сделайте запуск только для теста намеренно медленным, вызовите одну и ту же команду с блокировкой дважды на тестовом наборе данных и убедитесь, что второй вызов сообщает о конфликте блокировки, не записывая конкурирующий результат.
Включайте расписание только после проверки его вывода
sudo systemctl enable --now field-summary.timer
systemctl list-timers field-summary.timer --all
Проверьте следующее запланированное время, затем просмотрите первый запланированный результат. Храните время начала, время завершения, количество обработанных элементов и результат в логах скрипта. Отсутствие записи об успехе — это повод для проверки, а не доказательство того, что задание выполнялось. Обратитесь к командам timer и activation в systemctl.
Чтобы приостановить будущие запуски, используйте sudo systemctl disable --now field-summary.timer. Это не завершает уже запущенную службу. Если требуется прерывание, сначала установите, можно ли безопасно остановить её текущую запись. По мере роста объёма работы проверяйте длительность, повторы и лимиты внешних API; несколько машин требуют общей координации. Продолжите с сценарием персональных инструментов и упражнением по восстановлению для данных, которые поддерживает эта автоматизация.
Использованная документация
Основные ссылки для этой страницы. Проверьте документацию для версии, установленной в вашей среде.