Процессы, задания оболочки и сигналы
Файлы описывают подготовленное приложение, но работа выполняется процессами. У процесса есть идентификатор, владелец, родитель, состояние и открытые ресурсы. Если приложение не отвечает, важно сначала понять, какой процесс должен обслуживать запрос. Наличие строки с именем node не подтверждает, что это наш DeskQueue: на одной машине могут работать несколько приложений и вспомогательных команд.
Для опыта используем только собственный короткий процесс sleep в отдельном терминале лаборатории. Он не обращается к базе и не слушает порт. Мы будем наблюдать его, временно останавливать и завершать. Команды в статье предназначены для повторения читателем; при подготовке серии никакие процессы сервера не создавались и не завершались.
Получаем известный идентификатор
Запустите sleep в фоне и сразу сохраните идентификатор. Переменная $! содержит PID последнего фонового задания, запущенного этой оболочкой. Наше имя переменной явно относится к опыту, чтобы не спутать его с постоянным идентификатором службы.
sleep 300 &
lab_sleep_pid=$!
printf 'lab pid=%s\n' "$lab_sleep_pid"
ps -p "$lab_sleep_pid" -o pid,ppid,user,stat,etime,args
Ожидается одна строка с выбранным PID и аргументами sleep 300. Число зависит от машины. Родителем обычно будет текущая оболочка, но особенности запуска могут влиять на дерево. Посмотрите владельца и время работы. Эти сведения помогают проверить, что наблюдаете именно созданный объект, а не другой процесс с похожим именем.
Команда ps показывает снимок на момент обращения. Через секунду состояние может измениться. Исчезнувшая строка не всегда является ошибкой: программа могла завершиться нормально. Поэтому при сравнении наблюдений учитывайте время и ожидаемую длительность работы. Для постоянно работающей службы понадобится отдельный менеджер, который связывает процесс с её именем и политикой перезапуска.
Задание принадлежит оболочке
Команда jobs -l показывает задания текущей интерактивной оболочки. Их номера, например %1, отличаются от PID. Второй терминал может не знать этих заданий, хотя сами процессы видны системе. Это важное различие: job удобен для управления сеансом, а PID относится к объекту системы.
jobs -l
Знак & оставляет выполнение в фоне и возвращает возможность вводить команды. Он не превращает программу в надёжную службу. После закрытия сеанса её поведение зависит от сигналов, оболочки и способа запуска. Для приложения, которое должно работать независимо от терминала, позже подготовим deskqueue.service, вместо того чтобы считать фоновой символ полноценным сопровождением.
Если запустить sleep 300 без &, команда займёт передний план. Нажатие Ctrl+Z обычно посылает сигнал остановки и возвращает приглашение оболочки. Это именно остановка выполнения, а не просто «перемещение в фон». Команда bg может продолжить остановленное задание в фоне, а fg — вернуть его на передний план. Читайте состояние, чтобы не спутать остановленный процесс с работающим.
Состояние и расход ресурсов
В поле STAT есть буквы, обозначающие состояние и дополнительные признаки. Например, ожидание и остановка выражают разные причины отсутствия вычислений. Процесс, ожидающий ввод или таймер, не обязан расходовать заметное процессорное время. У нашего sleep ожидание является самой задачей, поэтому низкая нагрузка не говорит о зависании.
В справке ps для Ubuntu описаны поля и варианты выбора. Здесь используем явный список столбцов, чтобы результат было удобно обсуждать. Для поиска настоящей проблемы недостаточно одного состояния: свяжите процесс с журналом и ресурсом, который он ожидает. Статус описывает симптом, но не всегда раскрывает причину.
Не считайте зомби обычным процессом, который можно завершить повторным сигналом. Его выполнение уже закончилось, а запись о завершении ещё должна быть обработана родителем. Такой случай требует понимания дерева процессов. Он отличается от работающего приложения с высокой нагрузкой и от остановленного задания вашей оболочки. Одинаковое действие для всех этих состояний не имеет смысла.
Сигнал выражает намерение
Для завершения нашего известного sleep используем TERM. Перед отправкой ещё раз прочитайте его аргументы, затем дождитесь завершения через wait. Операция относится только к процессу, который вы создали и чей PID сохранили в этом же опыте.
ps -p "$lab_sleep_pid" -o pid,args
kill -TERM "$lab_sleep_pid"
wait "$lab_sleep_pid"
printf 'wait status=%s\n' "$?"
Ожидается завершение от сигнала и соответствующий ненулевой статус ожидания. Это не отказ учебного опыта: мы сами выбрали такой способ остановки. При нормальном завершении программа может вернуть ноль. Поэтому в документе наблюдения нужно указать действие и ожидаемый исход, иначе ненулевое число будет ошибочно принято за новую неисправность.
TERM даёт приложению возможность обработать завершение, например закрыть соединения. KILL такой возможности не даёт. Для собственного sleep разница мало заметна, но для сервера с записью данных она существенна. Выбор сигнала должен учитывать договор приложения и время завершения. Начинать с принудительного уничтожения только ради быстрого исчезновения строки — слабая процедура сопровождения.
Имя не определяет единственный объект
Широкий поиск по слову node может найти оболочку с командой поиска, редактор, другой сервис и несколько экземпляров нашего приложения. Поэтому сначала ограничьте наблюдение владельцем, родителем, аргументами или системой управления службой. Не переносите учебный приём с известным PID на все процессы с совпавшим именем. Это разные уровни уверенности в выбранном объекте.
PID также может повторно использоваться после завершения. Сохранённое вчера число не является постоянным адресом приложения. Для длительных операций менеджер службы и её control group дают более устойчивую связь с экземпляром. В нашей короткой лаборатории идентификатор читается сразу после запуска, а управление происходит в том же сеансе, что делает происхождение объекта понятным.
У веб-сервера завершение обычно имеет этапы: прекратить приём новых операций, дождаться текущих в пределах выбранного срока и закрыть ресурсы. Поэтому отправленный TERM и исчезнувший процесс являются двумя разными наблюдениями. Если программа не завершается, сначала рассмотрите её журнал и договор остановки. Менеджер службы сможет ограничить ожидание, но это ограничение тоже нужно согласовать с длительностью запросов, а не выбирать случайное число.
В evidence/processes.md запишите PID, владельца, аргументы, способ запуска и завершения. Уберите из отчёта предположение, что любой фоновой процесс является службой. Результат урока — понимание снимка процесса и состояния задания, а также аккуратная операция с собственным объектом. Далее systemd свяжет приложение с конфигурацией, журналом и управляемым жизненным циклом.