Отслеживание Upstart неправильный PID процесса - не возрождается

11

Я изначально задавал этот вопрос на StackOverflow. Потом понял, что это, наверное, лучшее место.

У меня есть настройка bluepill для мониторинга моих процессов delayed_job. (Приложение Ruby On Rails)

Использование Ubuntu 12.10.

Я запускаю и отслеживаю сам сервис bluepill с помощью Ubuntu upstart. Моя выскочка конфигурации ниже ( /etc/init/bluepill.conf).

description "Start up the bluepill service"

start on runlevel [2]
stop on runlevel [016]

expect daemon
exec sudo /home/deploy/.rvm/wrappers/<app_name>/bluepill load /home/deploy/websites/<app_name>/current/config/server/staging/delayed_job.bluepill

# Restart the process if it dies with a signal
# or exit code not given by the 'normal exit' stanza.
respawn

Я также пытался с expect forkвместо expect daemon. Я также попытался удалить expect...линию полностью.

Когда машина загружается, bluepill запускается нормально.

$ ps aux | grep blue
root      1154  0.6  0.8 206416 17372 ?        Sl   21:19   0:00 bluepilld: <app_name>

PID процесса bluepill здесь 1154. Но, upstartкажется, отслеживает неправильный PID. Он отслеживает PID, который не существует.

$ initctl status bluepill
bluepill start/running, process 990

Я думаю, что это отслеживает PID sudoпроцесса, который запустил процесс bluepill.

Это предотвращает возрождение процесса bluepill, если я принудительно убью bluepill с помощью kill -9.

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

В чем может быть проблема здесь?

ОБНОВЛЕНИЕ :

Проблема остается на сегодня (3 мая 2015 года) на Ubuntu 14.04.2.

Проблема не в использовании sudo. Я больше не использую sudo. Моя обновленная конфигурация выскочки:

description "Start up the bluepill service"

start on runlevel [2]
stop on runlevel [016]

# Restart the process if it dies with a signal
# or exit code not given by the 'normal exit' stanza.
respawn

# Give up if restart occurs 10 times in 90 seconds.
respawn limit 10 90

expect daemon

script
    shared_path=/home/deploy/websites/some_app/shared

    bluepill load $shared_path/config/delayed_job.bluepill
end script

Когда машина загружается, программа загружается нормально. Но выскочка все еще отслеживает неправильный PID, как описано выше.

Обходной путь, упомянутый в комментариях, может исправить проблему зависания. Я не пробовал, хотя.

Anjan
источник
Вы пытались посмотреть, что такое процесс 990? ps aux | grep 990должен сделать это, но pstree 990может быть более информативным.
Оли
Никакого процесса с PID 990 не существует.
Анжан
2
что касается необходимости перезагрузки, чтобы выскочить обратно в хорошее состояние - посмотрите этот хороший инструмент: github.com/ion1/workaround-upstart-snafu
andersonbd1
и вы можете ускорить этот инструмент с помощью этой команды: $ echo 3000 | sudo tee / proc / sys / kernel / pid_max
andersonbd1

Ответы:

8

Довольно поздно, но, надеюсь, это может помочь другим пользователям.

В upstart есть задокументированная ошибка, которая может привести к тому, что initctl отследит неверный PID, если указать неверный forkраздел в конфигурации upstart: https://bugs.launchpad.net/upstart/+bug/406397.

Что происходит, так это то, что upstart проверяет forkраздел и определяет, сколько разветвленных процессов он должен проверить, прежде чем выбрать «истинный» PID контролируемой программы. Если вы укажете expect forkили, expect daemonно ваша программа не разветвляется достаточное количество раз, startзависнет. Если, с другой стороны, ваш процесс разветвляется слишком много раз, он initctlбудет отслеживать неправильный PID. Теоретически, это должно быть задокументировано в этом разделе готовой поваренной книги , но, как вы можете видеть в этой ситуации, есть PID, связанный с уничтоженным процессом, когда его не должно быть.

Последствия этого объясняются в комментариях к багтрекеру, но я здесь подведу итог: помимо initctlнеспособности остановить процесс демона и застрять в недокументированном / недопустимом состоянии <service> start/killed, process <pid>, если процесс, принадлежащий этому PID, останавливается (и обычно это будет ) затем PID освобождается для повторного использования системой.

Если вы введете initctl stop <service>или service <service> stop, initctlубьет этот PID в следующий раз, когда он появится. Это означает, что где-то в будущем, если вы не перезагрузите компьютер после этой ошибки, следующий процесс, использующий этот PID, будет немедленно уничтожен, initctlдаже если он не будет демоном. Это может быть что-то простое catили сложное ffmpeg, и вам будет трудно понять, почему ваш программный пакет завис в середине какой-то рутинной операции.

Таким образом, проблема заключается в том, что вы указали неправильную expectопцию для числа форков, которые фактически делает процесс демона. Они говорят, что есть переписывание выскочки, которое решает эту проблему, но по состоянию на выстреле 1.8 (последняя версия Ubuntu 13.04 / январь 2014) проблема все еще присутствует.

Поскольку вы использовали expect daemonи в конечном итоге с этой проблемой, я рекомендую попробовать expect fork.

Редактирование: Вот Ubuntu BASH-совместимый скрипт ( оригинальный Wade Fitzpatrick, модифицированный для использования Ubuntu sleep), который порождает процессы до тех пор, пока не будет исчерпано доступное адресное пространство идентификатора процесса, после чего он начинается с 0 и продолжается до «зависания» PID. Затем процесс запускается при зависании PID initctl, и initctlубивает его и сбрасывает.

#!/bin/bash

# usage: sh /tmp/upstart_fix.sh <pid>

sleep 0.001 &
firstPID=$!
#first lets exhaust the space
while (( $! >= $firstPID ))
do
    sleep 0.001 &
done

# [ will use testPID itself, we want to use the next pid
declare -i testPID
testPID=$(($1 - 1))
while (( $! < $testPID ))
do
    sleep 0.001 &
done

# fork a background process then die so init reaps its pid
sleep 3 &
echo "Init will reap PID=$!"
kill -9 $$
# EOF
Дакота
источник
Этот ответ содержит некоторую полезную и интересную информацию, однако мне непонятно, как этот ответ отвечает на первоначальный вопрос, так как @Anjan упомянул: «Я также пробовал с помощью
user12345
5

Для приведенного примера:

$ initctl status bluepill
bluepill start/running, process 990

быстрое решение для меня это:

# If upstart gets stuck for some job in stop/killed state
export PID=990
cd /usr/local/bin
wget https://raw.github.com/ion1/workaround-upstart-snafu/master/workaround-upstart-snafu
chmod +x workaround-upstart-snafu
./workaround-upstart-snafu $PID

источник: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=582745#37

Я надеюсь, что это будет полезно. Что происходит, объясняется в других ответах.

Szymon Jeż
источник
Хороший сценарий. Это может занять минуту или две. rebootИногда может быть предпочтительным , а также фиксирует это.
Петр Ильфрич
0

Если вы не запускаете задание уровня пользователя Upstart или не используете раздел setuid - тогда ваша работа выполняется от имени пользователя root.

Поскольку Upstart уже запущен от имени пользователя root, зачем вам вообще использовать sudo в вашем execразделе?

Использование sudoили suв execстрофе вызвало те же проблемы для меня, как вы описали здесь.

Обычно я испытываю пункт 1 ИЛИ 1 и 2:

  1. выскочка следует неверный PID
  2. выскочка зависает, когда я пытаюсь остановить процесс

Конечно, дополнительно вы должны указывать в expectстрофе правильное количество вилок.

YMMV, но для меня:

  • использование sudo или su в execстрофе с указанным правильным количеством вилок обычно приводит к ситуации 1 выше.
  • Неправильное количество указанных вилок (с нашими без sudo / su in exec) приводит к ситуации 1 И 2 ​​выше.
user12345
источник