RE:NODE

Эксплуатация13 мин чтения

Выражения cron простыми словами и расписания для игровых серверов

Пять полей cron, четыре оператора, ловушка дня недели и поведение часовых поясов - плюс расписания перезапуска, резервных копий и предупреждений, которые стоит запустить.

1 прочтений

Выражение cron - это пять полей через пробел, которые читаются слева направо: минута, час, день месяца, месяц, день недели. 0 5 * * * означает «в минуту 0 часа 5, каждый день» - пять утра. */15 * * * * означает «каждую пятнадцатую минуту, каждого часа, каждого дня». На этом девяносто процентов всего, и если вам нужен был только ночной перезапуск, дальше можно не читать.

Остальные десять процентов - то, где люди теряют выходные: поля дня месяца и дня недели ведут себя не так, как вы ждёте, если использовать оба сразу, */7 делает не то, что кажется, часовой пояс не тот, в котором сидите вы, а задача с задержкой в шестьдесят секунд после резервной копии не ждёт, пока копия завершится. В этой статье синтаксис разобран как следует, а затем описаны те немногие расписания, которые действительно стоит запускать на игровом сервере.

Пять полей#

ПозицияПолеДиапазонТакже принимает
1Минута0-59
2Час0-2324-часовой формат, без AM/PM
3День месяца1-31
4Месяц1-12JAN-DEC
5День недели0-7SUN-SAT; 0 и 7 - оба воскресенье

Присутствовать должны все поля. Поля для секунд и для года в стандартной пятипольной форме нет, так что самое мелкое разрешение - одна минута. Если планировщик перед вами просит шесть полей, то это либо системный crontab в /etc/crontab или /etc/cron.d, где шестая колонка - пользователь, от имени которого запускается задача, либо парсер в стиле Quartz, где первое поле - секунды. Это разные форматы, которые с первого взгляда неотличимы, и вставка выражения из одного в другой - частый способ добиться того, что задача сработает в шестьдесят раз чаще задуманного.

Названия нечувствительны к регистру, так что MON, Mon и mon - одно и то же. Диапазоны названий работают в большинстве реализаций - MON-FRI допустимо, - но шаги в сочетании с названиями переносимы не везде, так что пишите 1-5, а не MON-FRI/2, если хотите быть уверены.

Четыре оператора, и это всё#

  • *** - каждое значение.** * * * * * запускается раз в минуту, навсегда. Отличный способ проверить и ужасная вещь, чтобы оставлять её на месте.
  • `,` - список. 0,30 * * * * - в начале часа и в половину. В списках могут быть диапазоны: 0 2,6,14,22 * * *.
  • `-` - диапазон, включительно. 0 9-17 * * * - каждый час с 09:00 до 17:00, то есть девять запусков, а не восемь.
  • `/` - шаг. */15 в поле минут - это 0, 15, 30, 45. Шаг применяется к тому, что стоит слева от него, так что 0-30/10 - это 0, 10, 20, 30, а 5/10 в поле минут означает «начать с 5 и идти с шагом 10 до конца диапазона»: 5, 15, 25, 35, 45, 55.

Некоторые парсеры принимают и сокращённые псевдонимы вместо всех пяти полей: @hourly, @daily (он же @midnight), @weekly, @monthly, @yearly и @reboot. В crontab на Linux они удобны, а в полях панелей ненадёжны, потому что многие из них хотят пять настоящих полей. Пишите выражение целиком; оно длиннее на пять символов и работает везде.

Оператора для «последнего дня месяца», «первого четверга» или «каждой второй недели» нет. Парсеры в стиле Quartz добавляют для части этого L, W и #, стандартный cron - нет, а поле в панели обычно стандартное. Обходной путь описан ниже.

Примеры#

ВыражениеКогда срабатывает
0 5 * * *05:00 каждый день
45 4 * * *04:45 каждый день
*/15 * * * *Каждые 15 минут
0 */6 * * *00:00, 06:00, 12:00, 18:00
0 5 * * 105:00 каждый понедельник
30 3 * * 003:30 каждое воскресенье
0 4 1 * *04:00 первого числа месяца
0 4 1,15 * *04:00 первого и пятнадцатого
*/10 9-17 * * 1-5Каждые 10 минут, 09:00-17:50, по будням
0 3 * * 403:00 каждый четверг
17 2 * * *02:17 каждый день

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

Читайте незнакомое выражение, проходя поля по порядку и говоря между ними слово «из». 30 3 * * 0 - это «минута 30, из часа 3, из любого дня месяца, из любого месяца, в воскресенье». Эта привычка ловит большинство ошибок ещё до запуска.

Ловушка дня месяца и дня недели#

Это самое часто неверно понимаемое правило в cron, и оно стоило больше случайных вайпов, чем что-либо другое.

Если ограничены оба поля - день месяца и день недели, то есть ни одно не равно *, - cron запускает задачу, когда совпадает любое из них, а не когда совпадают оба. 0 0 13 * 5 не означает «полночь в пятницу тринадцатого». Оно означает «полночь каждого 13-го, а также полночь каждой пятницы», то есть примерно девять раз в месяц, а не один-два раза в год.

Когда одно из двух равно *, поведение обычное, какого вы и ждёте: 0 4 * * 1 - только по понедельникам, 0 4 15 * * - только пятнадцатого.

Итак, чтобы сказать «первый четверг месяца», одним cron не обойтись. На машине с Linux вы планируете запуск каждый четверг и защищаете его в самой команде:

bash
# 06:00 on the first Thursday of the month. Note the escaped % in a crontab.0 6 * * 4 [ "$(date +\%d)" -le 07 ] && /opt/scripts/wipe.sh >> /var/log/wipe.log 2>&1

В панели, где есть только поле cron и список команд, честный ответ таков: запускайте вручную, или запускайте каждый четверг и смиритесь, или планируйте разовый запуск на каждый месяц. Принудительный вайп в Rust - обычная причина таких вопросов, и статья вайпы без потери игроков доказывает, что объявление в любом случае важнее автоматизации.

Часовые пояса, смена времени и что значит «полночь»#

У cron нет собственного часового пояса. Он использует часы той машины, на которой работает: местное время на машине с Linux и настроенный часовой пояс панели в панели хостинга. Ни то ни другое не обязательно ваше. Игрок в Тбилиси, назначивший перезапуск 0 5 * * * на оборудовании в Германии, назначил его на 08:00 по своему времени зимой и на 07:00 летом, а это ни для кого не глубокий вечер и середина утра для него самого.

Отсюда два вывода.

Выясните, по каким часам вы работаете, прежде чем доверять расписанию. Самая быстрая проверка - поставить безобидную задачу - объявление в игре или echo на машине с Linux - на две минуты вперёд и посмотреть, сработает ли она, когда вы ждёте. Делайте это один раз для каждого хоста; это быстрее, чем читать чью-либо документацию.

Избегайте часов, когда переводятся стрелки. В ЕС, включая немецкое оборудование, на котором работаем мы, часы перескакивают вперёд в 02:00 по местному времени в последнее воскресенье марта и назад в 03:00 по местному времени в последнее воскресенье октября. При переходе вперёд часа с 02:00 до 02:59 не существует, а при переходе назад он происходит дважды. Разные реализации cron решают это по-разному - одни пропускают, другие запускают с опозданием, третьи запускают дважды, - и ни с одной не стоит спорить. Назначайте обслуживание на 04:00 или 05:00, и вопрос не возникнет. Если вам действительно нужны точные интервалы через смену времени, запускайте машину и расписание по UTC.

Расписания, которые стоит иметь на игровом сервере#

Четыре расписания предотвращают большую часть того, о чём люди открывают обращения. Время ниже предполагает, что в пять утра никто не играет; сдвигайте блок целиком, сохраняя порядок.

ВыражениеЗадачаЗачем
40 4 * * *Объявить о перезапуске через 20 минутНикто не потеряет постройку
50 4 * * *Команда сохранения, затем резервная копияВ копии будут последние десять минут
0 5 * * *ПерезапускОчищает утечки, сущности, фрагментацию
0 4 * * 0Еженедельная резервная копия, сохранённая и заблокированнаяТа, из которой восстанавливаются после плохой недели

Команду сохранения перед резервной копией пропускают чаще всего. Резервная копия - это копия файлов на диске, а большинство игровых серверов держат мир в памяти и записывают его по таймеру. Копия без предварительного сохранения даёт архив того, как выглядел мир на момент последнего автосохранения, а это могло быть двадцать пять минут назад. Отправьте save-all в Minecraft, save в консоли Valheim, saveworld или его аналог в том, что вы запускаете, подождите минуту, затем делайте копию.

Помимо этих четырёх, добавьте то, что нужно вашей игре: дамп базы данных по собственному расписанию, если она у вас есть (резервные копии и восстановление баз данных), дневное сохранение и объявление на строительном сервере, ротацию логов, если игра пишет собственные (логи, которые стоит хранить). Краткая версия этого списка - задачи по расписанию, которые стоит иметь, а как часто слишком часто, разобрано в статье расписания перезапусков, которые помогают.

Порядок задач, задержки и пересекающиеся запуски#

Расписание в панели - это обычно одно выражение cron с несколькими задачами под ним, у каждой из которых есть задержка в секундах после предыдущей. Эта задержка - ожидание, а не проверка завершения. Это важнее, чем кажется:

  1. Задача первая: отправить save-all. Задержка 60 секунд.
  2. Задача вторая: создать резервную копию. Задержка 60 секунд.
  3. Задача третья: перезапустить сервер.

Выглядит верно, но это не так. Резервная копия сервера на 30 GB занимает минуты, а перезапуск срабатывает через шестьдесят секунд после начала копии, а не после её завершения. Вы получаете перезапуск посреди операции архивации и архив, который может оказаться пригодным, а может и нет. Решение - дать копии запас, несколько минут задержки, подобранных под ваш мир, или, лучше, вынести перезапуск в отдельное расписание 0 5 * * *, пока копия идёт в 50 4 * * *. Два расписания с разницей в десять минут проще осмыслить, чем одно с угаданной задержкой.

В crontab на Linux эквивалентная проблема - задача, которая работает дольше своего интервала. */5 * * * * для скрипта, который иногда работает семь минут, даёт две копии, дерущиеся за одни и те же файлы. Оберните:

bash
*/5 * * * * flock -n /tmp/sync.lock /opt/scripts/sync.sh >> /var/log/sync.log 2>&1

flock -n либо берёт блокировку, либо сразу сдаётся, так что вторая копия завершается, а не запускается. Это одно слово, и оно убирает целый класс инцидентов.

Вкладка Schedules на RE:NODE принимает выражение cron и список упорядоченных задач с задержками, а задача - одно из трёх: консольная команда, резервная копия или действие с питанием. Слоты резервных копий есть на каждом тарифе, копию можно заблокировать, чтобы ротация её не удаляла, а сами копии хранятся вне машины, которую они защищают. Это покрывает всю таблицу выше без единого скрипта. Пошаговая версия есть в руководстве по расписаниям, а почему планировщик живёт в панели, а не внутри вашего сервера, объясняет статья как панель устроена изнутри.

Crontab на машине с Linux: дополнительные правила#

Если вы на VDS, а не в панели, у cron есть несколько особенностей, которые не имеют отношения к выражению и всё равно ломают задачи.

  • Правьте через `crontab -e`, смотрите через `crontab -l`. Ручная правка файлов очереди - способ получить crontab, который молча не загружается.
  • `PATH` почти пуст. Cron не читает профиль вашей оболочки. node, docker и всё, что лежит в /usr/local/bin, может не находиться. Используйте в команде абсолютные пути или задайте PATH= в начале crontab.
  • `%` означает перевод строки. В команде crontab неэкранированный % превращается в разрыв строки, а всё после первого попадает задаче на стандартный ввод. date +%Y превращается в date + и лишнюю строку. Экранируйте каждый как \%.
  • Вывод отправляется почтой, а не в лог. Если почтовой системы нет, вывод уходит в никуда. Перенаправляйте его сами через >> /var/log/job.log 2>&1, а MAILTO="" в начале crontab задайте, если хотите тишины.
  • Системные crontab принимают поле пользователя. Файлы в /etc/cron.d и /etc/crontab имеют шесть колонок, где пользователь стоит между полем дня недели и командой. Строка из пяти колонок в этих файлах не работает.

Для всего, где есть настоящая цепочка зависимостей, таймеры systemd лучше cron: они пишут в журнал, могут зависеть от других юнитов, а systemctl list-timers показывает, когда следующий запуск, чего cron не сделает никогда. Для работы, которую запускает приложение, а не часы, вам нужна очередь: фоновые задачи на небольшом сервере.

Ошибки, которые стоят выходных#

***/7 * * * * - это не каждые семь минут.** Шаги начинаются заново с начала каждого часа, так что оно срабатывает в минуты 0, 7, 14, 21, 28, 35, 42, 49, 56, а затем снова в 0 через четыре минуты. У любого шага, не делящего 60, каждый час есть короткий промежуток. Используйте 5, 10, 15, 20 или 30.

**0 0 * * * на общей машине.** Полночь - самая загруженная минута суток на любом узле. Перенесите.

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

Расписание резервных копий, из которого никто не восстанавливался. Резервная копия, из которой вы ни разу не восстанавливались, - это гипотеза. Выберите тихую неделю и проверьте восстановление до того, как оно понадобится.

Забытое расписание. Через полгода какая-то задача всё ещё чистит каталог, где теперь лежит другое. Записывайте замысел в название расписания и раз в сезон просматривайте список расписаний.

FAQ#

Что означает */15 * * * *?

Каждую пятнадцатую минуту каждого часа: 00, 15, 30 и 45 минут. */15 - это шаг в поле минут; остальные четыре звёздочки означают, что ограничений по часу, дате, месяцу или дню недели нет.

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

Две обычные причины - правило дня месяца и дня недели (если заданы оба поля, cron срабатывает, когда совпадает любое) и часовой пояс, который принадлежит хосту или панели, а не вам. Проверьте оба, прежде чем считать планировщик сломанным.

Может ли cron запускать что-то каждые 30 секунд?

Сам по себе нет; минимальный интервал - одна минута. Запускайте задачу каждую минуту и пусть она внутри себя ждёт 30 секунд и повторяется, или используйте таймер systemd с OnUnitActiveSec=30s, или поместите цикл в саму программу, которой это нужно.

Что должно быть первым - резервная копия или перезапуск?

Сначала резервная копия, с командой сохранения перед ней, затем перезапуск с комфортным запасом. Копия, сделанная во время завершения работы, - это копия сервера, который завершает работу, а копия, начатая за шестьдесят секунд до перезапуска, может не успеть закончиться.

Нужно ли что-то перезапускать после правки crontab?

Нет. Cron перечитывает файл после сохранения через crontab -e. В панели расписание вступает в силу сразу после сохранения, а надёжнее всего подтвердить это, один раз поставив его на пару минут вперёд и посмотрев, как оно сработает.

Какой часовой пояс использует расписание в панели?

Тот, что настроен для панели, а это обычно расположение оборудования, а не ваше. Наше работает в Германии, так что местное время там смещается на час между летом и зимой. Проверьте безобидной задачей, прежде чем доверять окно обслуживания расписанию.


Комментарии

Полностью анонимно: без аккаунта, без почты, без cookie. Мы храним имя, которое вы ввели, текст и время - больше ничего. Количество ссылок ограничено, разметка не отображается.

0/2000