Я немного поискал и не нашел похожих вопросов.
У меня есть работа, которая должна выполняться каждые пять минут.
Одновременно должно выполняться только одно задание.
Если программа запускается более 5 минут, она должна запуститься немедленно, а не ждать.
В большинстве случаев работа выполняется менее чем за минуту, иногда она должна выполнять действия, которые могут занять до 20 минут.
В настоящее время я запускаю это задание как службу systemd, и задание представляет собой сценарий оболочки, который вызывает фактическую программу в цикле и засыпает между итерациями (5 минут - время последнего выполнения). Отлично работает.
#!/bin/sh
#
# Sample executable repeat-loop
#
# Run my job in a loop. If it takes less than max_delay seconds
# to run, sleep until it's time to repeat. If, for some reason, it took longer, just start
# over again immediately.
max_delay=300 # maximum delay between runs
# Don't allow multiple copies of this script to run
[ "${FLOCKER}" != "$0" ] && exec env FLOCKER="$0" flock -en "$0" "$0" "$@"
restart=0
now=0
while true ; do
now=`date -u '+%s'`
if [ $restart -gt $now ] ; then
sleep `expr $restart - $now`
fi
restart=`expr $now + ${max_delay}`
echo "my job runs here and may take between 30 seconds and 20 minutes to execute"
done
Так как я чертов идиот, я подумал, что было бы здорово изменить это на сервис с одним выстрелом и сработать таймеры systemd.
Я не смог понять, как имитировать такое поведение, используя OnUnitActiveSec
или OnUnitInactiveSec
...
OnUnitActiveSec
будет запускать мой сервис onehot каждые x секунд. OnUnitInactiveSec
собирается запустить мой onehot через x секунд после того, как последний раз был прерван.
Есть мысли, кроме "Эй, ваш сценарий оболочки отлично работает, зачем бить себя мертвой лошадью?"
Я должен был лучше протестировать, чем полагаться на мою (неправильную) интерпретацию документов.
Создание файла таймера и использование OnUnitActiveSec
указывая на служебный файл, который Type=simple
делает именно то, что я хочу. Таймер будет запускаться каждые 5 минут, если процесс длится более 5 минут, он будет вызываться (почти) немедленно. Он не будет вызываться дважды.
Важно использовать simple
вместо того oneshot
(согласно документации).