У меня есть набор тестов, который запрашивает локальный сервер. Для работы сервера должен быть запущен процесс сервера. Возможно, процесс уже запущен для отладки, но может и не быть. Если серверный процесс запущен, можно с уверенностью предположить, что он правильный. Если мы запустили процесс, мы должны убить его, когда мы закончим, но если он уже был запущен, мы должны оставить его.
Я написал сценарий bash, который, кажется, работает, но не совсем идеален.
if [ -z `pgrep -x server-process` ]; then
mkdir ./data
server-process ./data &
sleep 1; # Wait for server to print output,
# reporting initialization details etc.
fi
# Set up environment variables...
run-test-suite $@
if jobs %1 2>/dev/null; then
kill %1
rm -R ./data;
fi
В частности:
- Есть ли более надежный способ сделать это?
- Есть ли какие-то крайние случаи, которые я пропустил?
- Есть ли лучший способ подождать
server-process
исходный результат, а неsleep 1
(который в любом случае часто бывает недостаточно длинным)?server-process
не закрывает канал — он все равно может сообщать об ошибках — я не возражаю, если они чередуются с выходными данными набора тестов. Я просто хочу подождать, пока сервер не распечатает исходную информацию о конфигурации.
2 ответа
Захват вывода pgrep
и проверка того, что он пуст, не кажется лучшим способом использовать эту утилиту, учитывая, что она возвращает истинное значение, когда находит один или несколько процессов:
if ! pgrep -x server-process >/dev/null 2>&1
then
mkdir ./data
server-process ./data &
sleep 1; # Wait for server to print output,
# reporting initialization details etc.
fi
Использование спецификаций вакансий с %1
удобство для интерактивных оболочек. Мы можем написать более надежный код, используя $!
:
server_pid=0
if
then
server-process ./data &
server_pid=$!
fi
Это имеет то преимущество, что портативный — т.е. мы можем использовать /bin/sh
как переводчик, а не требовать /bin/bash
.
Фактически, вместо того, чтобы запоминать pid и условно использовать его в конце скрипта, мы можем сразу зарегистрировать действие, которое нужно предпринять:
if
then
server-process ./data &
trap "kill $!; rm -r ./data" EXIT
fi
Если нет веской причины для создания каталога данных внутри текущего рабочего каталога, вероятно, лучше использовать mktemp
чтобы создать нам красивый пустой начальный каталог.
Собираем все вместе:
#!/bin/sh
set -eu
if ! pgrep -x server-process >/dev/null 2>&1
then
data_dir=$(mktemp -d)
server-process "$data_dir" &
trap "kill $!; rm -r '$data_dir'" EXIT
sleep 1; # Wait for server to initialise
fi
run-test-suite "$@"
Не зная подробностей server-process
Я могу только догадываться, но, возможно, есть лучшая альтернатива произвольному sleep
. Возможно, существует файл, чье появление в $data_dir
может указывать на то, что сервер можно использовать? Или сокет, который начинает отвечать?
Добро пожаловать в Code Review, Ари.
Хорошо
- отступ
- полезные комментарии
Основные предложения
- Что касается вашего серверного процесса: было бы неплохо, если бы у него был соответствующий сценарий «init» для его запуска. В systemd-land все изменилось, и вы должны следовать этому стилю, если ваша система основана на systemd. В любом случае, правильная настройка init / systemd упростит жизнь вашим администраторам и разработчикам.
- Если вы находитесь в systemd-land, тогда ваш
systemctl start
позаботится об ожидании начала процесса. Если вы находитесь в зоне инициализации, вам нужно будет найти другой способ проверить, что процесс запущен. Есть ли сообщение журнала, которого вы можете дождаться, или сокет, который вы можете проверить? Если вы просто ждете вывода, перенаправьте его в файл и дождитесь, пока он что-нибудь будет содержать. Как-нибудь найдите что-нибудь для проверки и зацикливайтесь, пока это не произойдет. - Как только у вас будет чистый способ его запуска, вы можете удалить фоновый фон на своем серверном процессе и засыпание после него. Команда запуска (в любом стиле) не должна завершаться, пока ваш процесс не будет запущен.
- Ваш сценарий запуска также должен обрабатывать остановку, поэтому вам не нужно больше проверять, работает ли он. Просто запустите свой скрипт с аргументом stop (или запустите systemctl), и он исчезнет. Если он умер раньше, вы можете получить сообщение. Но тогда вы можете удалить дерево данных.
Маленькие гниды
- Не нужно заканчивать строки точкой с запятой. Оболочка принимает каждую строку как команду, если в конце строки нет обратной косой черты. Используя точку с запятой, поставьте
then
в той же строке, что иif
хорошо. Это один из часто встречающихся примеров помещения нескольких команд в одну строку. - Используйте двойные квадратные скобки для условных выражений, чтобы избежать сюрпризов.
- Попробуйте shellcheck. В нем будут некоторые предложения, которые я не учел.
- Поместите каталог в переменную, а затем обратитесь к этим переменным вместо
./data
.