Как процесс может умереть так, что Process.wait не заметит? - PullRequest
0 голосов
/ 28 сентября 2018

У меня есть этот скрипт ruby ​​для управления 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

Скрипт работает хорошо уже пару месяцев.На днях я обнаружил вещи в состоянии, в котором выполнялся скрипт, но оба дочерних процесса были мертвы.

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

Как мог дочерний процесс умереть, если родительский сценарий не знал?

Ответы [ 2 ]

0 голосов
/ 22 октября 2018

Зомби не единственная возможная причина этой проблемы - о остановленных детях может не сообщаться по разным причинам.

Существование зомби обычно означает, что родитель не ожидал их должным образом.Тем не менее, опубликованный код выглядит нормально, поэтому, если где-то не скрывается ошибка фреймворка, я бы хотел выйти за рамки апокалипсиса зомби, чтобы объяснить эту проблему.

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

На некоторых платформах Ruby может добавить флаг, запрашивающий возврат остановленных дочерних элементов, о которых не было сообщено, используя следующий синтаксис:

waitpid(pid, Process::WUNTRACED)

AFAIK waitall didn 'у него нет версии, которая принимает флаги, поэтому вам придется объединять ее самостоятельно или использовать pid = -1 для ожидания любого дочернего процесса (по умолчанию, если вы опустите pid) или pid = 0 для ожидания любого дочернего процесса с тем же процессомgroupID как вызывающий процесс.

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

0 голосов
/ 17 октября 2018

Как мог дочерний процесс умереть без ведома родительского сценария?

Я предполагаю, что дочерний процесс превратился в зомби и пропустил 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!'

Поскольку ваш вопрос носит общий характер, он трудендать вам конкретный ответ.

...