Как процесс может погибнуть так, что Process.wait не заметил бы?
У меня есть этот рубиновый скрипт для управления процессами que. que не поддерживает мультипроцесс, см. обсуждение здесь):
#!/usr/bin/env ruby
cluster_size = 2
puts "starting Que cluster with #{cluster_size} workers"; STDOUT.flush
%w[INT TERM].each do |signal|
trap(signal) do
@pids.each{|pid| Process.kill(signal, pid) }
end
end
@pids = []
cluster_size.to_i.times do |n|
puts "Starting Que daemon #{n}"; STDOUT.flush
@pids << Process.spawn("que --worker-count $MAX_THREADS")
end
Process.waitall
puts "Que cluster has shut down"; STDOUT.flush
Сценарий работает уже пару месяцев. На днях я нашел вещи в состоянии, когда скрипт работал, но оба дочерних процесса были мертвы.
Я экспериментировал с попыткой воспроизвести это. Я убивал детей различными сигналами, если бы они делали исключения. Во всех случаях сценарий знал, что процесс умер и сам умер.
Как детский процесс мог погибнуть без знания родительского скрипта?
Ответы
Ответ 1
Как детский процесс мог погибнуть без знания родительского скрипта?
Я предполагаю, что детский процесс превратился в зомби и пропустил Process.waitall
. Вы проверяли, являются ли дети процессами зомби, когда это происходит?
Зомби: Если у вас есть процессы зомби, это означает, что их зомби не ждали их родители (проверьте PPID
с помощью ps -l
). В итоге у вас есть три варианта: исправить родительский процесс (заставить его ждать); убить родителя; или преодолеть это.
Не могли бы вы проверить свой список сигналов и trap
его?
Вы можете перечислить все доступные сигналы (см. Ниже в окнах):
Signal.list
=> {"EXIT"=>0, "INT"=>2, "ILL"=>4, "ABRT"=>22, "FPE"=>8, "KILL"=>9, "SEGV"=>11, "TERM"=>15}
Не могли бы вы попытаться trap
его, например, INT
(примечание: вы можете иметь одну ловушку для сигнала) (
Signal.trap('SEGV') { throw :sigsegv }
catch :sigsegv
start_what_you_need
end
puts 'OMG! Got a SEGV!'
Поскольку ваш вопрос является общим, трудно дать вам конкретный ответ.
Ответ 2
Зомби - не единственная возможная причина для этой проблемы - дети с остановкой могут не сообщаться по целому ряду причин.
Существование зомби обычно означает, что родитель не подождал должным образом. Однако опубликованный код выглядит нормально, поэтому, если там не обнаруживается ошибка структуры, я бы хотел посмотреть за пределы апокалипсиса зомби, чтобы объяснить эту проблему.
В отличие от зомби, которые невозможно полностью получить, поскольку у них нет доступного родителя, замороженные процессы имеют неповрежденного родителя, но по какой-то причине перестали отвечать на запросы (ожидание внешнего процесса или операции ввода-вывода, проблемы с памятью, длинные или бесконечные цикл, медленные операции с базой данных и т.д.).
На некоторых платформах Ruby может добавить флаг, запрашивающий возврат остановленных детей, которые не были отправлены, используя следующий синтаксис:
waitpid(pid, Process::WUNTRACED)
waitall
не имеет версии, которая принимает флаги, поэтому вам придется ее заполнить самостоятельно или использовать pid = -1
для ожидания любого дочернего процесса (по умолчанию, если вы опускаете pid) или pid = 0
чтобы ждать любой дочерний объект с той же самой группой процессов, что и вызывающий процесс.
См. Документацию здесь.