In our application we have the problem with high CPU load and hang process when upload of the file failed (user press Esc, network failure ....)
The problem inside a method out in cgi_process.rb when Rails run under passenger and the way how the rescue_in_public working
def out(output = $stdout)
convert_content_type!
set_content_length!
output.binmode if output.respond_to?(:binmode)
output.sync = false if output.respond_to?(:sync=)
begin
output.write(@cgi.header(@headers))
if @cgi.send(:env_table)['REQUEST_METHOD'] == 'HEAD'
return
elsif @body.respond_to?(:call)
# Flush the output now in case the @body Proc uses
# #syswrite.
output.flush if output.respond_to?(:flush)
@body.call(self, output)
else
output.write(@body)
end
output.flush if output.respond_to?(:flush)
rescue Errno::EPIPE, Errno::ECONNRESET
# lost connection to parent process, ignore output
end
end
if connection to parent process is lost under passenger, then error from .flush is Errno::ESPIPE, not catched here, dispatch.rb catches it and calls failsafe_response. We happens to use "Exception Notifier" plugin, so we get the email with original error and process id and immediate look at the server shows that the process with this id is hanging with
_llseek(5, -1, 0xbfd03664, SEEK_CUR) = -1 ESPIPE (Illegal seek) _llseek(5, -1, 0xbfd03664, SEEK_CUR) = -1 ESPIPE (Illegal seek) _llseek(5, -1, 0xbfd03664, SEEK_CUR) = -1 ESPIPE (Illegal seek) _llseek(5, -1, 0xbfd03664, SEEK_CUR) = -1 ESPIPE (Illegal seek) _llseek(5, -1, 0xbfd03664, SEEK_CUR) = -1 ESPIPE (Illegal seek)I've just added this code into plugins require 'action_controller/cgi_process'
module ActionController
class CgiResponse
def out_with_espipe(*args)
begin
out_without_espipe(*args)
rescue Errno::ESPIPE => exception
begin
message = exception.to_s + "\r\n" + exception.backtrace.join("\r\n")
RAILS_DEFAULT_LOGGER.fatal(message)
#NonwebNotifier.deliver_exception_notification(exception, {})
rescue Exception => e
$stderr.write("Exception #{e.to_s} in handling exception #{exception.to_s}")
end
end
end
alias_method_chain :out, :espipe
end
end