timeout завершил проверку: отличаем лимит времени от ошибки команды
Пакетная проверка иногда ждёт ответа бесконечно. Инженер добавляет timeout, но затем любой ненулевой результат называет «истёкшим временем». В итоге настоящий отказ программы с кодом 2 уходит в повторные попытки, а пропавшая утилита тоже выглядит как медленная работа. Ограничить время недостаточно: нужно понять, кто сформировал код завершения.
GNU timeout запускает отдельную команду и при превышении срока посылает ей сигнал, по умолчанию TERM. Без --preserve-status истечение лимита обычно обозначается кодом 124. Если команда успела завершиться сама, возвращается её статус. Есть и собственные ошибки запуска timeout, которые требуют другой реакции.
Проверим границу без внешних сервисов
Вместо реальной проверки используем sleep. Этот пример запускает только короткий дочерний процесс и показывает, какая ветка выполнена.
#!/bin/sh
if timeout -k 1s 0.2s sleep 2; then
printf '%s\n' 'Проверка завершилась вовремя'
else
status=$?
case "$status" in
124) printf '%s\n' 'Достигнут лимит времени' ;;
125|126|127) printf 'Не удалось запустить проверку: %s\n' "$status" >&2 ;;
137) printf '%s\n' 'Получен KILL; нужен разбор причины' >&2 ;;
*) printf 'Проверка завершилась с ошибкой: %s\n' "$status" >&2 ;;
esac
fi
Ожидаемая ветка — «Достигнут лимит времени». Значение -k 1s задаёт дополнительный срок после первого сигнала: если процесс продолжит работать, последует KILL. Это не общий лимит в одну секунду от начала запуска. Для обычного sleep дополнительное принудительное завершение не понадобится.
Сроки меньше секунды удобны только для учебной проверки. В рабочем задании выбирайте интервал по нормальному времени операции и допустимой задержке результата. Слишком короткий лимит превращает обычные колебания времени в повторные ошибки и может увеличить нагрузку за счёт повторов.
Не путайте окончание ожидания с отменой действия
Завершение локальной программы не доказывает, что удалённая операция не состоялась. Если команда отправила запрос на публикацию, а ответ задержался, повтор способен создать дубль. Перед добавлением retry проверьте, есть ли у операции идентификатор запроса или безопасная проверка уже созданного результата.
Даже локальная команда может успеть записать часть файла. Для генерации отчёта пишите в отдельный кандидат и принимайте его только после успешного завершения. Сам факт существования выходного файла после timeout не означает, что файл закончен.
Код 137 означает получение KILL и не позволяет одним числом отличить все причины такого завершения. Не подписывайте его автоматически как «операция превысила лимит». Сохраните stderr, команду запуска без секретов и собственные временные отметки, чтобы разбирать обстоятельства, а не восстанавливать их по одному числу.
Выберите, что ограничивать
timeout запускает исполняемую программу, а не произвольную shell-строку. Если операция состоит из нескольких команд, вынесите её в отдельный скрипт либо явно вызовите shell с фиксированным текстом. Не склеивайте внешние данные в текст sh -c: передавайте их позиционными аргументами.
Для интерактивной программы существует --foreground, но при нём меняется управление группой процессов и дочерние процессы не охватываются тем же способом. Для пакетной проверки этот режим обычно не нужен. Перед применением к программе, порождающей свои дочерние задачи, проверьте её штатный механизм отмены и дождитесь завершения всех участников.
В курсе Linux и Bash скрипты строятся с проверкой ошибок. Откройте программу и продолжите к автоматизации, где ограничение времени, повтор и итоговый статус связаны с реальным состоянием операции, а не только с последней строкой лога.
Ещё по теме
Продолжить на практике
- Linux и Bash для DevOps-инженеров ↗
Linux для работы с серверами: процессы, права, systemd, сеть, диски и логи. Автоматизируйте повседневные задачи на Bash и разберите типичные сбои сервиса — от занятого порта до переполненного диска.
