Хобрук: Ваш путь к мастерству в программировании

Как убить процесс, прочитав файл pid с помощью сценария bash в Jenkins?

Внутри Jenkins мне нужно запустить 2 отдельных скрипта: start.sh и stop.sh. Эти сценарии находятся внутри моего приложения, которое извлекается из SCM. Они находятся внутри одного каталога.

Сценарий start.sh запускает процесс в фоновом режиме, используя nohup, и записывает processId в save_pid.pid. Этот скрипт работает нормально. Он успешно запускает мое приложение.

Затем внутри stop.sh я пытаюсь прочитать processId из save_pid.pid, чтобы удалить процесс. Но я не могу удалить процесс, и приложение продолжает работать, пока я не уничтожу процесс вручную, используя: sudo kill {processId}.

Вот подходы, которые я уже пробовал внутри stop.sh, но ни один из них не работает:

kill $(cat /path/to/save_pid.pid)

kill `cat /path/to/save_pid.pid`

kill -9 $(cat /path/to/save_pid.pid)

kill -9 `cat /path/to/save_pid.pid`

pkill -F /path/to/save_pid.pid

Я также пробовал все эти шаги с sudo. Но это просто не работает. Я сохранил оператор echo внутри stop.sh, который печатает, а затем ничего не происходит.

Что я здесь делаю неправильно?

ОБНОВЛЕНИЕ:

Команда nohup, которую я использую внутри start.sh, выглядит примерно так:

nohup deploy_script > $WORKSPACE/app.log 2>&1 & echo $! > $WORKSPACE/save_pid.pid

Обратите внимание:

В моем случае значение, записанное внутри save_pid.pid, на удивление всегда меньше на 1, чем фактическое значение processId. !!!

18.11.2017

  • Вы уверены, что содержимое /path/to/save_pid.pid действительно является PID процесса, который вы хотите убить? 18.11.2017
  • Да, я так думаю. Поскольку stop.sh не работает, я вручную читаю содержимое save_pid.pid, а затем сам удаляю процесс, используя: sudo kill {processId} . После этого приложение останавливается. Итак, я думаю, это правильный pid. 18.11.2017
  • Вы проверяли вывод ошибки скрипта? Если kill по какой-то причине не работает, должно появиться сообщение об ошибке, которое должно дать некоторые подсказки. 18.11.2017
  • Как вы предположили в первом комментарии, я только что заметил кое-что странное. Когда я проверил, значение внутри save_pid.id : оно всегда на 1 меньше фактического processId, и я имею в виду всегда !!! . Как я узнал, на самом деле внутри start.sh nohup запускает мое приложение через порт 9005. И когда я перечислил все открытые порты и соответствующие процессы, я увидел processId, соответствующий 9005, всего 1 больше, чем содержание save_pid.id. Как это возможно ? Кроме того, я проверил результат работы stop.sh. Удивительно, но там нет ничего, кроме заявления echo, которое я там хранил. 18.11.2017
  • Обратите внимание, что ошибки будут напечатаны как stderr, а не stdout. Если вы не можете найти, где печатается stderr, вы можете временно перенаправить его в целях отладки, написав как kill -9 ... 2>&1. Что касается того, почему PID отличается, кажется, что все, что создает файл PID, делает это неправильно. (Не записывать правильный PID для уничтожения, чтобы завершить процесс.) 18.11.2017
  • Я обновил свой вопрос с помощью команды nohup, которая создает процесс. Не могли бы вы посмотреть на это? 18.11.2017
  • Это выглядит хорошо для меня. В целях отладки я бы добавил строку из deploy_script в echo my real pid = $$ и добавил ее в файл с >>, а не с >, чтобы убедиться, что мы видим все выполняемые процессы, и один не перезаписывает другой. 18.11.2017
  • Я внес изменения в stop.sh, как вы предложили выше: kill -9 cat /path/to/save_pid.pid 2>&1. Но я все еще не вижу ничего, кроме оператора эха. А что касается deploy_script , я не могу его изменить, потому что он автоматически генерируется во время каждой сборки системой сборки моего приложения. 18.11.2017
  • Получение логов из kill больше не важно. Мы знаем, почему это не работает, потому что PID неверен. Настоящая проблема заключается в том, чтобы выяснить, почему это так. Мне интересно, может ли сценарий развертывания запускаться несколько раз, один сценарий перезаписывает файл PID, написанный другим. 18.11.2017
  • Ну, я только что запустил эти скрипты в своей локальной среде. Значение внутри save_pid.pid соответствует фактическому processId. Кроме того, мне удалось остановить процесс с помощью stop.sh. Интересно, Jenkins что-то делает. 18.11.2017
  • Интересная проблема (+1), надеюсь, кто-нибудь сможет ответить! 18.11.2017
  • Да, в самом деле ! . В качестве временного обходного пути на данный момент я использую stop.sh, чтобы завершить процесс, используя порт, на котором он запущен. Я уверен, что это не лучший способ, поскольку есть сценарии, в которых несколько процессов могут прослушивать порт. Но я использую его сейчас только как обходной путь. И он работает в моем случае. 18.11.2017

Ответы:


1

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

Смотреть:

$ echo "/bin/sleep 10" > /tmp/foo
$ chmod +x /tmp/foo
$ nohup /tmp/foo & echo $!
[1] 26787
26787
nohup: ignoring input and appending output to 'nohup.out'
$ pgrep sleep
26789

Таким образом, «nohup» будет выполнять «оболочку», «оболочка» разветвит вторую «оболочку», чтобы выполнить «спящий режим», однако я могу сосчитать здесь только два процесса, поэтому я не могу учитывать один созданный PID.

Обратите внимание, что если вы поместите nohup и pgrep в одну строку, то pgrep, по-видимому, будет запускаться быстрее, чем оболочка, которая «спит» exec, и, таким образом, pgrep ничего не даст, что несколько подтверждает мою теорию:

$ nohup /tmp/foo & echo $! ; pgrep sleep
[2] 26899
nohup: ignoring input and appending output to 'nohup.out'
$

Если вы запустите свой процесс напрямую, то nohup "выполнит" ваш процесс и, таким образом, сохранит тот же PID для процесса, что и сам nohup (см. http://sources.debian.net/src/coreutils/8.23).-4/src/nohup.c/#L225) :

$ nohup /bin/sleep 10 & echo "$!"; pgrep sleep
[1] 27130
27130
nohup: ignoring input and appending output to 'nohup.out'
27130

Кроме того, если вы «exec» «спите» внутри скрипта, то будет создан только один процесс (как и ожидалось):

$ echo "exec /bin/sleep 10" > /tmp/foo
$ nohup /tmp/foo & echo "$!"; pgrep sleep
[1] 27309
27309
nohup: ignoring input and appending output to 'nohup.out'
27309

Таким образом, согласно моей теории, если бы вы «выполнили» свой процесс внутри скрипта, вы бы получили правильный PID.

18.11.2017
  • Я пробовал: nohup deploy_script > $WORKSPACE/app.log 2>&1 & echo $! > $WORKSPACE/save_pid.pid; pgrep sleep, но это не сработало. На самом деле разница между созданным идентификатором и фактическим идентификатором теперь равна 2. 19.11.2017
  • Это не сработало в том смысле, что даже после добавления pgrep sleep к моему скрипту nohup, как я показал в своем предыдущем комментарии, я все еще не получаю точное processId внутри save_pid.pid. 19.11.2017
  • pgrep sleep не поможет вам получить PID процесса. PID выключен на 2, потому что очевидно, что PID, который вы получаете, является PID shell, который выполняет ваш скрипт, а не PID процесса, который вы запускаете. Чтобы получить PID процесса, который вы запускаете, вам нужно вывести echo $! внутри скрипта. 19.11.2017
  • Хорошо. Проблема в моем случае в том, что я не могу изменить файл deploy_script. Он автоматически генерируется системой сборки моего приложения каждый раз, когда я запускаю приложение. Что вы предлагаете мне делать в таком случае? Мне все еще нужно запустить скрипт в фоновом режиме. 19.11.2017
  • nohup deploy_script > $WORKSPACE/app.log 2>&1 & echo $(( $! - 1 )) > $WORKSPACE/save_pid.pid но это точно уродливый хак! 19.11.2017
  • Ну, я вижу, что U уменьшает счет на 1. На самом деле, я думал об этом уродливом хаке раньше ;) . Но я не пошел с этим. Из википедии: Under Unix, process IDs are usually allocated on a sequential basis, beginning at 0 and rising to a maximum value which varies from system to system. Once this limit is reached, allocation restarts at zero and again increases. However, for this and subsequent passes any PIDs still assigned to processes are skipped . Так что, я думаю, все еще есть крошечный шанс вернуться к нулю или есть шанс, что следующий номер будет пропущен. 19.11.2017
  • Новые материалы

    Что такое гибкие методологии разработки программного обеспечения
    Что представляют собой гибкие методологии разработки программного обеспечения в 2023 году Agile-методологии разработки программного обеспечения заключаются в следующем: И. Введение A...

    Ториго  — революция в игре Го
    Наш следующий вызов против ИИ и для ИИ. Сможет ли он победить людей в обновленной игре Го? Обратите внимание, что в следующей статье AI означает искусственный интеллект, а Goban  —..

    Простое развертывание моделей с помощью Mlflow — Упаковка классификатора обзоров продуктов NLP от HuggingFace
    Как сохранить свои модели машинного обучения в формате с открытым исходным кодом с помощью MLFlow, чтобы позже получить возможность легкого развертывания. Сегодня модели упаковки имеют несколько..

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

    Раскрытие возможностей НЛП: часть речевой маркировки и ее проблемы
    В сфере обработки естественного языка (NLP) маркировка частей речи (POS) выступает в качестве фундаментального метода, позволяющего компьютерам понимать и анализировать человеческий язык на..

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

    Как реализовать линейную регрессию в JavaScript
    Узнайте, как реализовать линейную регрессию в JavaScript с помощью ML.js Линейная регрессия — это метод машинного обучения, используемый для моделирования связи между зависимой переменной и..