Rack app that forks, loads the rackup config in the child process, processes a single request, and exits. The response is communicated over a unidirectional pipe.
# File lib/shotgun/loader.rb, line 100 100: def assemble_app 101: config = @config 102: inner_app = self.inner_app 103: Rack::Builder.new { 104: instance_eval(&config) 105: run inner_app 106: }.to_app 107: end
# File lib/shotgun/loader.rb, line 17 17: def call(env) 18: dup.call!(env) 19: end
# File lib/shotgun/loader.rb, line 21 21: def call!(env) 22: @env = env 23: @reader, @writer = IO.pipe 24: 25: Shotgun.before_fork! 26: 27: if @child = fork 28: proceed_as_parent 29: else 30: Shotgun.after_fork! 31: proceed_as_child 32: end 33: end
# File lib/shotgun/loader.rb, line 73 73: def format_error(error, backtrace) 74: "<h1>Boot Error</h1>" + 75: "<p>Something went wrong while loading <tt>#{escape_html(rackup_file)}</tt></p>" + 76: "<h3>#{escape_html(error)}</h3>" + 77: "<pre>#{escape_html(backtrace.join("\n"))}</pre>" 78: end
# File lib/shotgun/loader.rb, line 109 109: def inner_app 110: if rackup_file =~ /\.ru$/ 111: config = File.read(rackup_file) 112: eval "Rack::Builder.new {( #{config}\n )}.to_app", nil, rackup_file 113: else 114: require rackup_file 115: if defined? Sinatra::Application 116: Sinatra::Application.set :reload, false 117: Sinatra::Application.set :logging, false 118: Sinatra::Application.set :raise_errors, true 119: Sinatra::Application 120: else 121: Object.const_get(File.basename(rackup_file, '.rb').capitalize) 122: end 123: end 124: end
Stuff that happens in the child process
# File lib/shotgun/loader.rb, line 83 83: def proceed_as_child 84: boom = false 85: @reader.close 86: status, headers, body = assemble_app.call(@env) 87: Marshal.dump([:ok, status, headers.to_hash], @writer) 88: spec_body(body).each { |chunk| @writer.write(chunk) } 89: rescue Object => boom 90: Marshal.dump([ 91: :error, 92: "#{boom.class.name}: #{boom.to_s}", 93: boom.backtrace 94: ], @writer) 95: ensure 96: @writer.close 97: exit! boom ? 1 : 0 98: end
Stuff that happens in the parent process
# File lib/shotgun/loader.rb, line 38 38: def proceed_as_parent 39: @writer.close 40: rand 41: result, status, headers = Marshal.load(@reader) 42: body = Body.new(@child, @reader) 43: case result 44: when :ok 45: [status, headers, body] 46: when :error 47: error, backtrace = status, headers 48: body.close 49: [ 50: 500, 51: {'Content-Type'=>'text/html;charset=utf-8'}, 52: [format_error(error, backtrace)] 53: ] 54: else 55: fail "unexpected response: #{result.inspect}" 56: end 57: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.