АйТи Фреш
Главная / Статьи / DevOps и автоматизация
DevOps и автоматизация

Задание systemd идёт дольше интервала таймера: будет ли вторая копия и почему следующий запуск сразу

Автор: Семёнов Евгений Сергеевич, директор ООО «АйТи-Фреш» · · ~24 мин чтения
Задание systemd идёт дольше интервала таймера: будет ли вторая копия и почему следующий запуск сразу
Иллюстрация к статье «Задание systemd идёт дольше интервала таймера: будет ли вторая копия и почему следующий запуск сразу».

Обмен настроен на каждые десять минут, а идёт двадцать пять. Сисадмин смотрит в top, видит вечно занятый процессор и начинает считать, сколько параллельных копий скрипта там крутится. Отвечаю сразу: ни одной лишней. Вторую копию systemd не запустит никогда. Но при этом ваш сервер и правда молотит без остановки — и это совсем другая поломка, у которой есть точная причина в устройстве таймеров и три разных способа лечения. Ниже — что реально происходит между таймером и службой, почему после завершения задание стартует мгновенно, чем OnUnitActiveSec отличается от OnUnitInactiveSec, что даёт DeferReactivation= из systemd 257 и что делать, если у вас Debian 12 и никакого 257 нет.

Вторую копию systemd не запустит — это гарантия, а не везение

Начну с главного, потому что вокруг этого больше всего мифов. В systemd таймер не «запускает скрипт». Таймер активирует юнит службы. А активация уже работающей службы — это не запуск, это ничего. Формулировка в systemd.timer(5) предельно однозначная: если юнит, который надо активировать, на момент срабатывания таймера уже активен, он не перезапускается, а просто остаётся работать. И следом там же — фраза, которую я обычно прошу перечитать вслух: концепции порождения новых экземпляров службы в этом случае не существует.

То есть механизм такой. Таймер срабатывает, ставит задание на запуск связанной службы и сам переходит в подсостояние running. Пока служба активна, таймер следующее срабатывание вообще не планирует — он ждёт уведомления о том, что служба стала inactive, и только тогда пересчитывает время. Я специально проверил это по исходнику src/core/timer.c: в состоянии running пересчёт делается исключительно по деактивации запущенного юнита. Поэтому никакой очереди пропущенных срабатываний нет: если прогон шёл час при интервале десять минут, счётчик «должен шесть раз» нигде не пишется. Проверить состояние можно глазами: у самого юнита таймера подсостояние меняется между waiting (ждёт своего часа) и running (связанная служба сейчас работает).

# пока служба работает, таймер висит в состоянии running
$ systemctl status lms-sync.timer
● lms-sync.timer - Синхронизация с учебной платформой
     Loaded: loaded (/etc/systemd/system/lms-sync.timer; enabled)
     Active: active (running) since Mon 2026-09-07 09:00:04 MSK
    Trigger: n/a
   Triggers: ● lms-sync.service

# когда служба отработала — waiting и появляется Trigger
$ systemctl list-timers lms-sync.timer
NEXT                        LEFT     LAST                        PASSED  UNIT
Mon 2026-09-07 09:40:00 MSK 6min     Mon 2026-09-07 09:30:00 MSK 3min    lms-sync.timer

Единственное честное исключение — когда служба врёт о своём состоянии. Type=forking с неправильным PIDFile, или Type=simple, у которого ExecStart дёргает обёртку, а та уводит настоящую работу в фон и мгновенно возвращает управление. Тогда юнит переходит в inactive, хотя процесс живёт, и следующее срабатывание таймера действительно поднимет ещё одну копию. Так что если вы видите два одинаковых python-процесса — виноват не systemd, виноват ваш Type= или скрипт с nohup внутри. И отдельная классика: RemainAfterExit=yes на службе, которую дёргает повторяющийся таймер. Такая служба остаётся active навсегда после первого запуска, и таймер больше никогда ничего не сделает. В мане про это написано прямым текстом.

Если задача была просто «не допустить параллельных прогонов» — она уже решена самим systemd, и городить lock-файлы не нужно. Проблема, из-за которой вы сюда пришли, почти наверняка другая: не дубли, а отсутствие паузы между прогонами.

Откуда берётся «следующий запуск сразу после окончания»

А вот теперь настоящая беда. Календарный таймер вычисляет момент следующего срабатывания от момента предыдущего срабатывания. Не от завершения службы — от её запуска. А пересчитывает он это время в тот момент, когда служба завершилась. Пока прогон укладывается в интервал, разницы никто не замечает. Как только прогон стал длиннее интервала, вычисленное время следующего срабатывания оказывается в прошлом. А срабатывание в прошлом systemd отрабатывает немедленно. Служба закончилась — и тут же стартует снова.

Это не баг и не моя интерпретация, это дословно описано в systemd.timer(5) в разделе про DeferReactivation=: поведение по умолчанию таково, что юнит таймера немедленно срабатывает снова, как только служба завершилась; так происходит потому, что таймер планирует следующее срабатывание от предыдущего времени срабатывания, и, поскольку интервал короче времени работы службы, это срабатывание оказывается в прошлом.

Разберём по шагам на живом примере — OnCalendar=*:0/10 и прогон в 25 минут. В 09:00 таймер срабатывает, служба стартует. В 09:10 и 09:20 не происходит ничего: таймер находится в состоянии running и ждёт завершения службы, новых срабатываний он не планирует, ни счётчика, ни очереди нет. В 09:25 служба завершается. Таймер считает следующее срабатывание от 09:00 плюс интервал, получает 09:10, видит, что это прошлое, и запускает службу немедленно. В 09:50 она завершается — и всё повторяется. Формально расписание соблюдено. Фактически у вас непрерывный цикл без единой секунды простоя.

Симптом на глаз узнаётся мгновенно: в journalctl записи Started и Finished идут встык, разрыв между окончанием одного прогона и началом следующего — ноль-две секунды, круглые сутки. При этом systemctl list-timers выглядит абсолютно здоровым, никаких ошибок, никаких failed. Именно поэтому такое живёт на серверах месяцами: мониторинг молчит, а пользователи просто жалуются, что «всё тормозит».

# считаем реальные интервалы между стартами за сутки
journalctl -u lms-sync.service --since -24h -o short-unix \
  | grep -F 'Starting ' | awk '{print $1}' \
  | awk 'NR>1{printf "%.0f сек\n", $1-p} {p=$1}' | sort -n | uniq -c
Не путайте это с Persistent=true. Persistent догоняет запуски, пропущенные из-за выключенной машины, и работает при активации таймера. Мгновенный перезапуск после долгого прогона — это штатная арифметика следующего срабатывания, Persistent тут вообще ни при чём.
Задание systemd идёт дольше интервала таймера: будет ли вторая копия и почему следующий запуск сразу — схема
Схема к статье. Открыть схему в полном размере

OnUnitInactiveSec= — интервал, который считается от финиша

Если вам нужна фраза «подожди пятнадцать минут после того, как всё закончилось», то в systemd она пишется ровно одним ключом. OnUnitInactiveSec= определяет таймер относительно момента, когда активируемый таймером юнит был в последний раз деактивирован. Не запущен — деактивирован. Это и есть честная пауза после окончания, без всяких надстроек и без оглядки на версию systemd: ключ существует с самых ранних версий и работает везде.

Рядом живёт похожий на вид OnUnitActiveSec=, и вот его путают постоянно. Он считает от момента последней активации службы. То есть ведёт себя ровно как календарный таймер: если прогон длиннее интервала, точка отсчёта уходит в прошлое и вы получаете тот же непрерывный цикл. Разница между двумя ключами — одно слово в названии и принципиально разное поведение под нагрузкой. Мой выбор по умолчанию для любого тяжёлого задания — Inactive.

Тонкость, на которой спотыкаются при первой настройке: монотонному таймеру нужен стартовый пинок. Пока служба ни разу не деактивировалась, отсчитывать не от чего, и таймер не сработает никогда. Поэтому OnUnitInactiveSec= всегда комбинируют с чем-то, что даёт первый запуск: обычно OnBootSec=, иногда OnActiveSec=. В мане это описано прямо: комбинируя OnBootSec= и OnUnitActiveSec=, можно определить таймер, который срабатывает через регулярные интервалы. С Inactive схема ровно такая же.

# /etc/systemd/system/lms-sync.timer
[Unit]
Description=Синхронизация с учебной платформой: пауза 10 минут ПОСЛЕ окончания

[Timer]
OnBootSec=3min
OnUnitInactiveSec=10min
AccuracySec=10s
Unit=lms-sync.service

[Install]
WantedBy=timers.target

Чего вы теряете, уйдя с календаря на монотонный таймер. Во-первых, Persistent= перестаёт действовать — он имеет эффект только на таймерах с OnCalendar=. Для задания, которое и так крутится каждые десять минут, это не потеря вообще. Во-вторых, привязка к стенным часам исчезает: прогоны будут плыть относительно круглых значений. Если бизнесу нужно строго «в 03:30 и ни минутой позже» — монотонный таймер не подходит, там нужен календарь. В-третьих, по формулировке мана монотонные часы при suspend, как правило, тоже встают на паузу (если не включён WakeSystem=), но для сервера в стойке это неактуально.

Одновременно «ровно каждые N минут по часам» и «пауза N минут после окончания» — взаимоисключающие требования, когда прогон бывает длиннее N. Выбирайте одно и проговаривайте выбор с заказчиком, иначе через месяц придёте к этой статье второй раз.
Памятка: OnUnitInactiveSec= — интервал, который считается от финиша — схема
Памятка: OnUnitInactiveSec= — интервал, который считается от финиша. Открыть схему в полном размере

DeferReactivation=yes: правильный ответ, если у вас systemd 257 и новее

В systemd 257 в календарные таймеры добавили булев ключ DeferReactivation= — в NEWS это пункт раздела CHANGES WITH 257 про Calendar .timer units. Формулировка из мана: когда он включён, таймер планирует следующее срабатывание исходя из перехода запускаемого юнита в неактивное состояние, а не из времени последнего срабатывания. И дальше — прямым текстом про наш случай: это наиболее заметно, когда служба работает дольше, чем интервал таймера; с включённой настройкой таймер запланирует следующее срабатывание от момента завершения службы, и ему придётся дождаться следующего календарного времени срабатывания.

Ключевое отличие от OnUnitInactiveSec= — календарная сетка сохраняется. Таймер не отсчитывает интервал от финиша, а просто перестаёт считать пропущенные срабатывания долгом и ждёт ближайшего подходящего момента по календарю. При OnCalendar=*:0/10 и прогоне с 09:00 до 09:25 служба стартует не мгновенно в 09:25, а в 09:30. Для заданий, которые логически привязаны к круглым значениям времени, это заметно приятнее монотонного таймера.

Ограничений из мана два, и оба важные. Первое: настройка имеет эффект только если задан реальный календарный таймер через OnCalendar=. С монотонными выражениями она молча игнорируется. Второе: по умолчанию false, то есть на всех ваших существующих таймерах поведение осталось старым, включать надо руками. И третье, уже не из мана, а из практики: systemd на неизвестный ключ в юните не падает — он пишет в журнал предупреждение (в 252 оно выглядит как Unknown key name 'DeferReactivation' in section 'Timer', ignoring., в новых версиях — Unknown key 'DeferReactivation' in section [Timer], ignoring.) и грузит юнит дальше как ни в чём не бывало. То есть на Debian 12 вы честно допишете DeferReactivation=yes, systemctl daemon-reload отработает без ошибки, а поведение не изменится ни на грамм.

# сначала версия — без этого не начинаем
$ systemctl --version | head -1
systemd 257 (257.13-1~deb13u1)

# и обязательная проверка юнита после правки
$ systemd-analyze verify /etc/systemd/system/lms-sync.timer
# молчание = ключ распознан; строка Unknown key … DeferReactivation = ваша версия его не знает

Что где стоит по состоянию на сентябрь 2026: Debian 12 bookworm — systemd 252.39, ключа нет; Ubuntu 24.04 LTS — 255.4, ключа нет; Debian 13 trixie — 257.13, ключ есть; Ubuntu 26.04 LTS — 259.5, ключ есть, а в разрабатываемом выпуске уже 261. Отдельно скажу, чего делать не надо: тащить systemd из backports или собирать его руками ради одного ключа. Оно того не стоит — OnUnitInactiveSec= решает ту же задачу на любой версии. Обновляйте дистрибутив по своему графику, а расписание чините тем, что есть под рукой. Бонусом в 258 появился RandomizedOffsetSec= — стабильный случайный сдвиг для OnCalendar=-таймеров, который, в отличие от RandomizedDelaySec=, сохраняет заданную периодичность событий даже при частых перезагрузках машины. Для парка машин, которые долбят один общий бэкап-сервер, штука полезная.

Никогда не выкатывайте DeferReactivation=yes на парк серверов без предварительной проверки версии на каждом. Юнит загрузится везде, ошибок не будет нигде, а работать оно начнёт только там, где systemd 257+. Это ровно тот класс правок, который создаёт иллюзию починки.

Разбор из практики: компьютерная школа «Терминал-школа», 31 рабочее место

Компьютерная школа «Терминал-школа»: 31 рабочее место — три учебных класса, преподавательская и администрация. Инфраструктура компактная: один сервер в собственной серверной с гипервизором, на нём файловый сервер с домашними папками учеников и отдельная Linux-виртуалка на Debian 12 (systemd 252.39, 4 vCPU, 8 ГБ) под обвязку — питоновский скрипт, который забирает с онлайн-платформы обучения списки групп, расписание и сданные домашние работы, раскладывает файлы по папкам учеников и отправляет обратно отметки о проверке. Пришли ко мне с формулировкой «сервер синхронизации постоянно загружен, в классах тормозит открытие файлов, наверное надо добавить ядер».

Что я увидел при разборе. Таймер с OnCalendar=*:0/10, служба Type=oneshot, скрипт исторически отрабатывал за три-четыре минуты. С началом учебного года число групп и сдаваемых работ выросло примерно втрое, и прогон растянулся до 25–40 минут. Load average на четырёх vCPU держался в диапазоне 8–11 круглосуточно, включая ночь и выходные, когда в классах никого нет. В journalctl за сутки — 43 прогона, идущих встык: разрыв между Finished и следующим Starting от нуля до двух секунд. Простоя у машины не было буквально ни минуты за трое суток.

Дальше — самое поучительное. До меня коллеги уже пытались это чинить и повесили на ExecStart обёртку с flock. Логика понятная: «наверное, там параллельные копии, надо заблокировать». Не помогло, и не могло помочь: параллельных копий не было изначально, systemd их и так не создаёт. flock ничего не заблокировал, потому что блокировать было нечего. Это самая частая диагностическая ошибка в этом сюжете, и на неё стабильно уходит день-два чужого времени.

Была и вторая, дорогая часть проблемы. API учебной платформы начал отдавать 429 Too Many Requests — непрерывная долбёжка без пауз вылезла за лимит запросов для учётной записи школы. Скрипт честно ретраил, ретраи удлиняли прогон, удлинившийся прогон гарантировал мгновенный перезапуск. Классическая положительная обратная связь: чем хуже, тем чаще, чем чаще, тем хуже. Добавление ядер, о котором просил клиент, эту петлю не разорвало бы вообще никак.

Лечение заняло полчаса. systemd 252, значит DeferReactivation= недоступен — перевёл таймер на монотонный. Плюс TimeoutStartSec= (для Type=oneshot он ограничивает весь прогон), чтобы зависший на сетевом таймауте прогон не держал юнит бесконечно, и уведомление на падение через OnFailure= — обратите внимание, этот ключ живёт в секции [Unit], а не [Service]. Вот что получилось:

# /etc/systemd/system/lms-sync.service
[Unit]
Description=Синхронизация с учебной платформой
Wants=network-online.target
After=network-online.target
OnFailure=notify-fail@%n.service

[Service]
Type=oneshot
User=sync
ExecStart=/opt/lms-sync/venv/bin/python /opt/lms-sync/run.py
TimeoutStartSec=2700

# /etc/systemd/system/lms-sync.timer
[Unit]
Description=Синхронизация с учебной платформой: пауза 10 минут после окончания

[Timer]
OnBootSec=3min
OnUnitInactiveSec=10min
AccuracySec=10s

[Install]
WantedBy=timers.target

Итог через две недели наблюдения. Прогонов в сутки стало 38–44 против прежних 43 — то есть полезной работы ровно столько же. Load average упал с 9,4 до 1,8 в среднем. Длительность одного прогона сократилась с 25–40 минут до 6–9: скрипт перестал конкурировать сам с собой за диск и, главное, перестал упираться в лимит API — ответы 429 исчезли полностью на третьи сутки. Жалобы преподавателей на медленное открытие файлов в классах прекратились, потому что виртуалка синхронизации больше не выедала общий дисковый массив непрерывными записями. Ядер не добавляли.

Отдельно проговорили с заказчиком то, о чём я писал выше: строгой привязки к круглым десяти минутам теперь нет, прогоны плывут. Ему это оказалось безразлично — важно было, чтобы сданная работа появлялась в папке ученика в течение получаса, а не красота расписания. Через полгода эту виртуалку переставили на Debian 13 и формально появилась возможность вернуться на OnCalendar= с DeferReactivation=yes. Не стали. Монотонный таймер работает, поведение всем понятно, трогать рабочее ради более модного ключа — плохая привычка.

Прежде чем просить у директора школы или любого другого клиента деньги на ядра и память, посчитайте паузы между прогонами. В моей практике каждый третий «нам не хватает ресурсов на сервере обмена» оказывается таймером, который перезапускает задание встык.
Цифры и версии: Разбор из практики: компьютерная школа «Терминал-школа», 31 рабочее место — схема
Цифры и версии: Разбор из практики: компьютерная школа «Терминал-школа», 31 рабочее место. Открыть схему в полном размере

Если DeferReactivation недоступен: что реально работает

Вариантов на самом деле немного, и я расставлю их по приоритету так, как расставляю у клиентов. Первый и основной — перевод на OnUnitInactiveSec=. Работает на любой версии systemd, поведение читается из юнита за пять секунд, ничего лишнего в системе не появляется. Если у задания нет жёсткой привязки к часам, дальше можно не читать, берите этот вариант.

Второй — просто увеличить интервал OnCalendar= с запасом относительно худшего наблюдаемого времени прогона. Способ туповатый, но у него есть законная ниша: когда разброс длительности небольшой и предсказуемый, а календарная сетка важна. Проблема в том, что запас имеет свойство съедаться ростом объёмов, и через полгода вы вернётесь к тому же самому. Обязательно вешайте на такой вариант мониторинг длительности.

Третий — разделить таймер и решение о запуске. Таймер дёргает лёгкий диспетчер каждую минуту, а тот сам смотрит на маркер последнего успешного завершения и решает, пора или нет. Гибко, позволяет описать любую логику вроде «не чаще раза в десять минут, но не в момент ночного бэкапа», и заодно даёт естественную точку для метрик. Плата — своя логика, которую надо сопровождать. Я иду на это, только когда правил действительно несколько.

А вот чего делать не стоит. Не надо ставить sleep в конец скрипта: юнит останется активным всё время сна, таймер всё это время просто ждёт, а systemctl status начнёт врать про длительность работы; к тому же при OnCalendar= пауза от sleep не спасёт от немедленного догона, если прогон вместе со сном длиннее интервала. Не надо навешивать flock, если единственная задача — пауза: параллельных копий и так нет, а лишняя обёртка усложняет диагностику. Не надо использовать Restart= на Type=oneshot службе как способ зациклить работу — Restart=always для oneshot вообще не допускается, а on-failure нужен для повторов после сбоя, а не для расписания. И не надо ставить StartLimitIntervalSec с расчётом «пусть systemd сам заглушит частые запуски»: он заглушит, но через failed-состояние юнита, и вы получите остановленное расписание вместо аккуратной паузы.

Отдельно про мониторинг, потому что описанная поломка мониторингом обычно не ловится. Ошибок нет, юниты зелёные, list-timers выглядит здорово. Ловить надо две метрики: длительность последнего прогона и время, прошедшее с последнего успешного завершения. Обе снимаются одной командой без единой сторонней утилиты:

# длительность последнего прогона и время с момента завершения
systemctl show lms-sync.service \
  -p ExecMainStartTimestampMonotonic \
  -p ExecMainExitTimestampMonotonic \
  -p Result -p NRestarts

# сколько прогонов было за сутки — если равно расписанию, всё в порядке
journalctl -u lms-sync.service --since -24h | grep -c 'Starting '
Мониторить надо не наличие ошибок, а факт и ритм выполнения. Задание, которое крутится непрерывно, и задание, которое не запускалось трое суток, одинаково не дают ни одной строчки в лог ошибок.

Чек-лист: с чего начать и на что можно забить

Порядок действий, если вы прямо сейчас смотрите на подозрительно занятый сервер. Сначала посчитайте паузы между прогонами за сутки — это одна команда из раздела выше, и она сразу разделяет две гипотезы. Если паузы нулевые, у вас описанный здесь сюжет, и лечится он правкой одного файла. Если паузы нормальные, а нагрузка всё равно высокая — проблема в самом задании, и таймер тут ни при чём, идите профилировать скрипт.

Дальше посмотрите systemctl --version и решите, доступен ли вам DeferReactivation=. Затем ответьте на единственный содержательный вопрос: нужна ли этому заданию привязка к стенным часам. Нужна и версия свежая — DeferReactivation=yes. Нужна, а версия старая — увеличенный интервал плюс мониторинг. Не нужна — OnUnitInactiveSec= и не думайте об этом больше. Заодно проверьте, нет ли где RemainAfterExit=yes на службе под повторяющимся таймером: это противоположная поломка, задание молча не выполняется вообще.

На что можно спокойно забить. На страх параллельных копий — их нет, гарантия записана в мане, lock-файлы под эту задачу не нужны. На точность до секунды: AccuracySec= по умолчанию минута, и для обменов, выгрузок и бэкапов этого более чем достаточно; выкручивать в 1us имеет смысл, только если вы точно знаете зачем, и заранее готовы к росту числа пробуждений процессора. На дискуссию cron против systemd timer: в 2026 году спорить не о чем, но и переписывать работающие crontab-строчки просто из принципа — пустая трата вечера.

И последнее, из области здравого смысла. Все описанные ключи — про то, когда задание запускается. Ни один из них не отвечает на вопрос, что делать с прогоном, который завис на сетевом таймауте и висит третий час. Для этого есть TimeoutStartSec= на службе, и я ставлю его всегда, даже когда уверен, что задание быстрое. Уверенность имеет свойство заканчиваться ровно в тот момент, когда у внешнего API отваливается плечо и ваш скрипт садится ждать ответа до конца времён.

Правка ровно одной строки в .timer-файле в моей практике снимала нагрузку с сервера сильнее, чем удвоение числа ядер. Это тот редкий случай, когда самое дешёвое решение оно же и самое правильное.
Порядок действий: Чек-лист: с чего начать и на что можно забить — схема
Порядок действий: Чек-лист: с чего начать и на что можно забить. Открыть схему в полном размере

Частые вопросы

Запустится ли вторая копия службы, если таймер сработал во время её работы?

Нет. В systemd.timer(5) сказано прямо: если активируемый юнит уже активен в момент срабатывания таймера, он не перезапускается, а просто остаётся работать, и концепции порождения новых экземпляров службы в этом случае не существует. Дубли процессов возможны только если сама служба врёт о своём состоянии — неправильный Type=forking, PIDFile или запуск работы в фон внутри скрипта.

Почему следующий запуск происходит сразу же после окончания предыдущего?

Потому что календарный таймер после завершения службы пересчитывает следующее срабатывание от предыдущего срабатывания, а не от момента завершения. Если прогон длился дольше интервала, вычисленное время оказывается в прошлом, и systemd отрабатывает его немедленно. Получается непрерывный цикл без пауз — при этом никаких ошибок в журнале нет и мониторинг молчит.

Чем OnUnitActiveSec= отличается от OnUnitInactiveSec=?

Точкой отсчёта. OnUnitActiveSec= считает от момента последней активации службы и при долгих прогонах даёт тот же мгновенный перезапуск, что и календарь. OnUnitInactiveSec= считает от момента последней деактивации, то есть даёт настоящую паузу после окончания работы. Для тяжёлых заданий нужен именно второй.

Работает ли DeferReactivation= вместе с OnUnitInactiveSec=?

Нет, и не нужно. В мане указано, что настройка имеет эффект только если задан календарный таймер через OnCalendar=. С монотонными выражениями она молча игнорируется. Да и смысла нет: OnUnitInactiveSec= уже отсчитывает интервал от завершения службы.

Что будет, если написать DeferReactivation=yes в systemd 252 или 255?

Ничего хорошего и ничего заметного. systemd запишет в журнал предупреждение о неизвестном ключе в секции [Timer] и проигнорирует строку, а юнит загрузится как валидный. Ошибки при daemon-reload не будет, поведение не изменится. Проверять надо через systemctl --version и systemd-analyze verify на файл таймера.

Поможет ли flock или lock-файл в скрипте?

От параллельных копий — да, но их и так нет, systemd их не создаёт. От непрерывного перезапуска встык — не поможет никак: блокировка снимается в момент завершения процесса, и следующий прогон стартует сразу же. Это самая частая ложная гипотеза при разборе такой ситуации.

Можно ли одновременно держать строгое расписание по часам и паузу после окончания?

Нет, если прогон бывает длиннее интервала — эти требования противоречат друг другу по определению. Ближайший компромисс — DeferReactivation=yes на systemd 257+: календарная сетка сохраняется, но после долгого прогона следующее время считается от момента завершения службы, поэтому мгновенного перезапуска нет — таймер ждёт ближайшего календарного момента.

Столкнулись с похожей задачей? Обращайтесь — решим

Если у вас происходит что-то из описанного в этой статье — или любая другая проблема с ИТ-инфраструктурой, — обращайтесь в любое время. Мои специалисты и я лично разберём ситуацию, найдём настоящую причину и доведём до решения.

Возьмёмся и за разовую задачу, и за постоянное обслуживание. Первичная консультация — бесплатно и без обязательств.

📞 +7 903 729-62-41 💬 MAX: +7 903 729-62-41 ✈ Telegram @ITfresh_Boss

С уважением, Семёнов Евгений Сергеевич, директор «АйТи Фреш» — IT-аутсорсинг для компаний до 50 рабочих мест, 15+ лет практики

Источники

© ООО «АйТи-Фреш» · Москва · Все статьи