Errno:: EPIPE: Исправлено исключение Broken pipe

if @block
  rd, wr = IO.pipe
  @pid = fork do
    $0 = "Forked child from Page #{@path}"
    rd.close
    result = @block.call(@resp.body)
    begin
    wr.write Marshal.dump(result)
  end
  wr.close

Это довольно стандартный способ совместного использования канала с вилкой, но как только rd.close вызывается, он разбивает трубку на wr для использования. До этой линии труба работает так, как должна (я запускал ее по строкам с помощью Pry). Насколько мне известно, хорошая практика заключается в том, чтобы закрыть читателя внутри вилки, чтобы остановить его вмешательство в отправку EOF (я не знаю, почему это работает, я просто знаю, что практика).

Это часть библиотеки, которую я вызываю в производственное приложение. Собственные спецификации библиотеки никогда не сталкиваются с этим, даже несмотря на то, что они используют очень похожий код (только @block и @resp будут отличаться в значительной степени). Очевидно, что код приложения более сложный, но я не вижу, как это будет мешать этому коду. Я искал в других библиотеках, требуемых приложением, чтобы увидеть, есть ли какие-либо сигналы захвата, которые могут помешать этому, но я ничего не нашел.

Может ли кто-нибудь предложить, что может быть проблемой или работать вокруг? Я попытался поймать исключение Errno::EPIPE и retry ing, но это не исправляет его, снова открывая трубку (я не совсем уверен, как это сделать в любом случае, так как после того, как развивается вилка, было бы сложно связать это к основному процессу), опорожняя блок, чтобы он не делал никакой работы... до сих пор нет радости.

Я также нашел (через комментарий этот вопрос), что Ruby Open3 в стандартной библиотеке тихо сохраняет и падает Errno::EPIPE, но не было причин, по которым зафиксировать сообщение. Я не знаю, связано ли это. https://github.com/ruby/ruby/blob/e3c288569833b6777e7ecc0bbc26f8e6ca8f2ba7/lib/open3.rb#L268

Любая помощь или понимание будут с благодарностью восприняты.

Ответ 1

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

def test_my_pipes
 rd, wr = IO.pipe  
 fork do  
   rd.close
   sleep 5
   wr.write "Hello world"
   wr.close
 end    
 wr.close  # essential
 puts "Waiting for sleepy fork"
 puts rd.read
 rd.close
end

Обратите внимание, что как внутри, так и снаружи блока fork мы закрываем как rd, так и wr. На самом деле wr.close только родительский процесс wr.close, но определенно лучше закрыть все концы трубы, когда в этом нет необходимости.

Если этот код все еще ломается, было бы интересно посмотреть, на какие версии ruby они ломаются.