Как процесс может погибнуть так, что 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 чтобы ждать любой дочерний объект с той же самой группой процессов, что и вызывающий процесс.

См. Документацию здесь.