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.