raptor 0.25.0 → 0.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.buildkite/pipeline.yml +34 -8
- data/AGENTS.md +25 -0
- data/CHANGELOG.md +35 -25
- data/README.md +82 -67
- data/Rakefile +10 -3
- data/lib/rackup/handler/raptor.rb +19 -12
- data/lib/raptor/binder.rb +17 -5
- data/lib/raptor/cli.rb +32 -2
- data/lib/raptor/cluster.rb +62 -141
- data/lib/raptor/embedded.rb +225 -0
- data/lib/raptor/plugin.rb +1 -0
- data/lib/raptor/reactor.rb +21 -4
- data/lib/raptor/version.rb +1 -1
- data/lib/raptor/worker.rb +200 -0
- data/sig/generated/rackup/handler/raptor.rbs +8 -8
- data/sig/generated/raptor/cli.rbs +5 -0
- data/sig/generated/raptor/cluster.rbs +22 -35
- data/sig/generated/raptor/embedded.rbs +93 -0
- data/sig/generated/raptor/plugin.rbs +1 -0
- data/sig/generated/raptor/worker.rbs +77 -0
- metadata +6 -1
data/lib/raptor/binder.rb
CHANGED
|
@@ -176,12 +176,18 @@ module Raptor
|
|
|
176
176
|
#
|
|
177
177
|
# @rbs () -> void
|
|
178
178
|
def parse
|
|
179
|
-
@
|
|
179
|
+
@listeners = []
|
|
180
|
+
@uri_listeners = {}
|
|
181
|
+
@bind_uris.each do |bind_uri|
|
|
180
182
|
uri = URI.parse(bind_uri)
|
|
181
183
|
filenos = @inherited_fds[bind_uri]
|
|
182
|
-
|
|
184
|
+
listeners = filenos ? restore_listeners(uri, filenos) : create_listeners(uri)
|
|
185
|
+
@uri_listeners[bind_uri] = listeners
|
|
186
|
+
@listeners.concat(listeners)
|
|
183
187
|
end
|
|
184
|
-
|
|
188
|
+
rescue
|
|
189
|
+
close
|
|
190
|
+
raise
|
|
185
191
|
end
|
|
186
192
|
|
|
187
193
|
# Creates fresh listeners for the given URI.
|
|
@@ -241,7 +247,9 @@ module Raptor
|
|
|
241
247
|
# @rbs (String? host, Integer? port) -> Array[TCPServer]
|
|
242
248
|
def create_tcp_listeners(host, port)
|
|
243
249
|
if host == "localhost"
|
|
244
|
-
|
|
250
|
+
listeners = []
|
|
251
|
+
loopback_addresses.each { |address| listeners.concat(create_tcp_listeners(address, port)) }
|
|
252
|
+
return listeners
|
|
245
253
|
end
|
|
246
254
|
|
|
247
255
|
host = host[1..-2] if host&.start_with?("[")
|
|
@@ -258,6 +266,10 @@ module Raptor
|
|
|
258
266
|
tcp_server = TCPServer.for_fd(socket.fileno)
|
|
259
267
|
socket.autoclose = false
|
|
260
268
|
[tcp_server]
|
|
269
|
+
rescue
|
|
270
|
+
listeners&.each(&:close)
|
|
271
|
+
socket&.close
|
|
272
|
+
raise
|
|
261
273
|
end
|
|
262
274
|
|
|
263
275
|
# Creates a Unix domain server socket at the given path. Removes stale
|
|
@@ -306,8 +318,8 @@ module Raptor
|
|
|
306
318
|
#
|
|
307
319
|
# @rbs (String? host, Integer? port, Hash[String, String] ssl_params) -> Array[SslListener]
|
|
308
320
|
def create_ssl_listeners(host, port, ssl_params)
|
|
309
|
-
tcp_servers = create_tcp_listeners(host, port)
|
|
310
321
|
ssl_context = build_ssl_context(ssl_params)
|
|
322
|
+
tcp_servers = create_tcp_listeners(host, port)
|
|
311
323
|
tcp_servers.map { |tcp_server| SslListener.new(tcp_server: tcp_server, ssl_context: ssl_context) }
|
|
312
324
|
end
|
|
313
325
|
|
data/lib/raptor/cli.rb
CHANGED
|
@@ -67,8 +67,11 @@ module Raptor
|
|
|
67
67
|
worker_shutdown_timeout: 30,
|
|
68
68
|
refork_after: (RUBY_PLATFORM.include?("linux") ? 1000 : nil),
|
|
69
69
|
before_fork: [].freeze,
|
|
70
|
+
after_fork: [].freeze,
|
|
70
71
|
before_worker_boot: [].freeze,
|
|
71
72
|
before_worker_shutdown: [].freeze,
|
|
73
|
+
after_worker_drain: [].freeze,
|
|
74
|
+
after_worker_exit: [].freeze,
|
|
72
75
|
before_refork: [].freeze,
|
|
73
76
|
plugins: [].freeze,
|
|
74
77
|
stats_file: "tmp/raptor.json",
|
|
@@ -175,11 +178,38 @@ module Raptor
|
|
|
175
178
|
#
|
|
176
179
|
# @rbs () -> void
|
|
177
180
|
def run
|
|
178
|
-
@command == :stats
|
|
181
|
+
if @command == :stats
|
|
182
|
+
run_stats
|
|
183
|
+
elsif @options[:workers].zero?
|
|
184
|
+
run_embedded
|
|
185
|
+
else
|
|
186
|
+
Cluster.run(@options)
|
|
187
|
+
end
|
|
179
188
|
end
|
|
180
189
|
|
|
181
190
|
private
|
|
182
191
|
|
|
192
|
+
# Serves in the CLI process until interrupted or terminated.
|
|
193
|
+
#
|
|
194
|
+
# @rbs () -> void
|
|
195
|
+
def run_embedded
|
|
196
|
+
require_relative "embedded"
|
|
197
|
+
|
|
198
|
+
$stdout.sync = true
|
|
199
|
+
$stderr.sync = true
|
|
200
|
+
|
|
201
|
+
Dir.chdir(@options[:chdir]) if @options[:chdir]
|
|
202
|
+
app = @options[:app] || Rack::Builder.parse_file(@options[:rackup])
|
|
203
|
+
server = Embedded.new(app, **@options, log: true).start
|
|
204
|
+
handlers = ["INT", "TERM"].to_h do |signal|
|
|
205
|
+
[signal, trap(signal) { Thread.new { server.shutdown } }]
|
|
206
|
+
end
|
|
207
|
+
server.join
|
|
208
|
+
ensure
|
|
209
|
+
server&.shutdown
|
|
210
|
+
handlers&.each { |signal, handler| trap(signal, handler) }
|
|
211
|
+
end
|
|
212
|
+
|
|
183
213
|
# Reads and prints the stats file.
|
|
184
214
|
#
|
|
185
215
|
# @return [void]
|
|
@@ -282,7 +312,7 @@ module Raptor
|
|
|
282
312
|
@options[:drain_accept_queue] = bool
|
|
283
313
|
end
|
|
284
314
|
|
|
285
|
-
opts.on("-w", "--workers NUM", Integer, "Number of worker processes (default: #{DEFAULT_WORKER_COUNT})") do |num|
|
|
315
|
+
opts.on("-w", "--workers NUM", Integer, "Number of worker processes, or 0 for in-process serving (default: #{DEFAULT_WORKER_COUNT})") do |num|
|
|
286
316
|
@options[:workers] = num
|
|
287
317
|
end
|
|
288
318
|
|
data/lib/raptor/cluster.rb
CHANGED
|
@@ -4,24 +4,19 @@
|
|
|
4
4
|
require "json"
|
|
5
5
|
require "time"
|
|
6
6
|
|
|
7
|
-
require "atomic-ruby/atomic_thread_pool"
|
|
8
7
|
require "concurrent/utility/processor_counter"
|
|
9
8
|
require "rack/builder"
|
|
10
|
-
require "ractor-pool"
|
|
11
9
|
|
|
12
10
|
require_relative "binder"
|
|
13
11
|
require_relative "control_server"
|
|
14
|
-
require_relative "http1"
|
|
15
|
-
require_relative "http2"
|
|
16
12
|
require_relative "log"
|
|
17
13
|
require_relative "plugin"
|
|
18
14
|
require_relative "raptor_native"
|
|
19
|
-
require_relative "reactor"
|
|
20
15
|
require_relative "reuseport_bpf"
|
|
21
|
-
require_relative "server"
|
|
22
16
|
require_relative "stats"
|
|
23
17
|
require_relative "systemd"
|
|
24
18
|
require_relative "version"
|
|
19
|
+
require_relative "worker"
|
|
25
20
|
|
|
26
21
|
module Raptor
|
|
27
22
|
# Forks and supervises worker processes. Handles graceful shutdown on
|
|
@@ -73,26 +68,23 @@ module Raptor
|
|
|
73
68
|
(cores.to_f / worker_count).round.clamp(1, HTTP2_RACTOR_COUNT_CAP)
|
|
74
69
|
end
|
|
75
70
|
|
|
76
|
-
# @rbs @drain_accept_queue: bool
|
|
77
71
|
# @rbs @worker_count: Integer
|
|
78
72
|
# @rbs @http1_ractor_count: Integer
|
|
79
73
|
# @rbs @http2_ractor_count: Integer
|
|
80
74
|
# @rbs @thread_count: Integer
|
|
81
75
|
# @rbs @max_thread_count: (Integer | Float)?
|
|
82
76
|
# @rbs @cpu_affinity: bool
|
|
83
|
-
# @rbs @clean_thread_locals: bool
|
|
84
|
-
# @rbs @clean_fiber_locals: bool
|
|
85
77
|
# @rbs @environment: String
|
|
86
|
-
# @rbs @connection_options: Hash[Symbol, untyped]
|
|
87
|
-
# @rbs @http1_options: Hash[Symbol, untyped]
|
|
88
|
-
# @rbs @http2_options: Hash[Symbol, untyped]
|
|
89
78
|
# @rbs @worker_boot_timeout: Integer
|
|
90
79
|
# @rbs @worker_timeout: Integer
|
|
91
80
|
# @rbs @worker_drain_timeout: Integer
|
|
92
81
|
# @rbs @worker_shutdown_timeout: Integer
|
|
93
82
|
# @rbs @before_fork: Array[Proc]
|
|
83
|
+
# @rbs @after_fork: Array[Proc]
|
|
94
84
|
# @rbs @before_worker_boot: Array[Proc]
|
|
95
85
|
# @rbs @before_worker_shutdown: Array[Proc]
|
|
86
|
+
# @rbs @after_worker_drain: Array[Proc]
|
|
87
|
+
# @rbs @after_worker_exit: Array[Proc]
|
|
96
88
|
# @rbs @before_refork: Array[Proc]
|
|
97
89
|
# @rbs @stats_file: String?
|
|
98
90
|
# @rbs @control_server: ControlServer?
|
|
@@ -103,12 +95,12 @@ module Raptor
|
|
|
103
95
|
# @rbs @access_log_io: IO?
|
|
104
96
|
# @rbs @launch_command: String?
|
|
105
97
|
# @rbs @launch_argv: Array[String]?
|
|
106
|
-
# @rbs @on_error: (^(Hash[String, untyped]?, Exception) -> void)?
|
|
107
98
|
# @rbs @binder: Binder
|
|
108
99
|
# @rbs @server_port: Integer
|
|
109
100
|
# @rbs @app: untyped
|
|
110
101
|
# @rbs @shutdown: bool
|
|
111
102
|
# @rbs @workers: Hash[Integer, Integer]
|
|
103
|
+
# @rbs @worker_indices: Hash[Integer, Integer]
|
|
112
104
|
# @rbs @timed_out: Set[Integer]
|
|
113
105
|
# @rbs @stats: Stats
|
|
114
106
|
# @rbs @started_at: Float
|
|
@@ -158,9 +150,12 @@ module Raptor
|
|
|
158
150
|
# @option options [Integer] :worker_drain_timeout seconds a worker waits for in-flight requests during shutdown before force-killing app threads
|
|
159
151
|
# @option options [Integer] :worker_shutdown_timeout seconds to wait for graceful worker exit before force-killing
|
|
160
152
|
# @option options [Integer, Array<Integer>, nil] :refork_after request-count threshold(s) at which a warm worker is promoted to a fork source for phased refork; nil or 0 disables. Requires `PR_SET_CHILD_SUBREAPER` (Linux)
|
|
161
|
-
# @option options [Array<Proc>] :before_fork procs called in the master before
|
|
153
|
+
# @option options [Array<Proc>] :before_fork procs called in the master before each direct worker fork, not seed forks
|
|
154
|
+
# @option options [Array<Proc>] :after_fork procs called in the master after each direct fork attempt, including failures
|
|
162
155
|
# @option options [Array<Proc>] :before_worker_boot procs called with the worker index before it begins serving
|
|
163
156
|
# @option options [Array<Proc>] :before_worker_shutdown procs called with the worker index before its graceful shutdown
|
|
157
|
+
# @option options [Array<Proc>] :after_worker_drain procs called with the worker index after draining, before exit or seed promotion
|
|
158
|
+
# @option options [Array<Proc>] :after_worker_exit procs called in the master after reaping, with the worker index, pid, and Process::Status
|
|
164
159
|
# @option options [Array<Proc>] :before_refork procs called in a worker before it transitions to a seed
|
|
165
160
|
# @option options [Array<String, Symbol>] :plugins plugins to load and start in order
|
|
166
161
|
# @option options [String, nil] :stats_file path to write per-worker stats JSON, or nil to disable
|
|
@@ -178,26 +173,23 @@ module Raptor
|
|
|
178
173
|
def initialize(options)
|
|
179
174
|
@options = options = options.dup
|
|
180
175
|
@plugins = []
|
|
181
|
-
@drain_accept_queue = options[:drain_accept_queue]
|
|
182
176
|
@worker_count = options[:workers]
|
|
183
177
|
@http1_ractor_count = options[:http1][:ractors] || self.class.default_http1_ractor_count(@worker_count)
|
|
184
178
|
@http2_ractor_count = options[:http2][:ractors] || self.class.default_http2_ractor_count(@worker_count)
|
|
185
179
|
@thread_count = options[:threads]
|
|
186
180
|
@max_thread_count = options[:max_threads]
|
|
187
181
|
@cpu_affinity = options[:cpu_affinity]
|
|
188
|
-
@clean_thread_locals = options[:clean_thread_locals]
|
|
189
|
-
@clean_fiber_locals = options[:clean_fiber_locals]
|
|
190
182
|
@environment = options[:environment] || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
|
|
191
|
-
@connection_options = options[:connection]
|
|
192
|
-
@http1_options = options[:http1]
|
|
193
|
-
@http2_options = options[:http2]
|
|
194
183
|
@worker_boot_timeout = options[:worker_boot_timeout]
|
|
195
184
|
@worker_timeout = options[:worker_timeout]
|
|
196
185
|
@worker_drain_timeout = options[:worker_drain_timeout]
|
|
197
186
|
@worker_shutdown_timeout = options[:worker_shutdown_timeout]
|
|
198
187
|
@before_fork = options[:before_fork] = Array(options[:before_fork]).dup
|
|
188
|
+
@after_fork = options[:after_fork] = Array(options[:after_fork]).dup
|
|
199
189
|
@before_worker_boot = options[:before_worker_boot] = Array(options[:before_worker_boot]).dup
|
|
200
190
|
@before_worker_shutdown = options[:before_worker_shutdown] = Array(options[:before_worker_shutdown]).dup
|
|
191
|
+
@after_worker_drain = options[:after_worker_drain] = Array(options[:after_worker_drain]).dup
|
|
192
|
+
@after_worker_exit = options[:after_worker_exit] = Array(options[:after_worker_exit]).dup
|
|
201
193
|
@before_refork = options[:before_refork] = Array(options[:before_refork]).dup
|
|
202
194
|
@stats_file = options[:stats_file]
|
|
203
195
|
@control_server = ControlServer.new(options[:control_url]) { stats_hash } if options[:control_url]
|
|
@@ -208,7 +200,6 @@ module Raptor
|
|
|
208
200
|
@access_log_io = nil
|
|
209
201
|
@launch_command = options[:launch_command]
|
|
210
202
|
@launch_argv = options[:launch_argv]
|
|
211
|
-
@on_error = options[:on_error]
|
|
212
203
|
|
|
213
204
|
Dir.chdir(options[:chdir]) if options[:chdir]
|
|
214
205
|
|
|
@@ -227,6 +218,7 @@ module Raptor
|
|
|
227
218
|
|
|
228
219
|
@shutdown = false
|
|
229
220
|
@workers = {}
|
|
221
|
+
@worker_indices = {}
|
|
230
222
|
@timed_out = Set.new
|
|
231
223
|
@stats = Stats.new(@worker_count)
|
|
232
224
|
@started_at = Process.clock_gettime(Process::CLOCK_REALTIME)
|
|
@@ -457,15 +449,34 @@ module Raptor
|
|
|
457
449
|
pid = spawn_worker_via_seed(index)
|
|
458
450
|
if pid
|
|
459
451
|
@workers[index] = pid
|
|
452
|
+
@worker_indices[pid] = index
|
|
460
453
|
return
|
|
461
454
|
end
|
|
462
455
|
Log.warn "Seed (#{@seed_pid}) failed to fork worker #{index}, falling back to direct fork"
|
|
463
456
|
@seed_pid = nil
|
|
464
457
|
end
|
|
465
458
|
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
459
|
+
master_pid = Process.pid
|
|
460
|
+
begin
|
|
461
|
+
@before_fork.each(&:call)
|
|
462
|
+
pid = fork { run_worker(index, @phase) }
|
|
463
|
+
@workers[index] = pid
|
|
464
|
+
@worker_indices[pid] = index
|
|
465
|
+
ensure
|
|
466
|
+
if Process.pid == master_pid
|
|
467
|
+
error = $!
|
|
468
|
+
@after_fork.each do |hook|
|
|
469
|
+
hook.call
|
|
470
|
+
rescue => hook_error
|
|
471
|
+
if error
|
|
472
|
+
Log.rescued_error(hook_error)
|
|
473
|
+
else
|
|
474
|
+
error = hook_error
|
|
475
|
+
end
|
|
476
|
+
end
|
|
477
|
+
raise error if error
|
|
478
|
+
end
|
|
479
|
+
end
|
|
469
480
|
end
|
|
470
481
|
|
|
471
482
|
# Asks the seed to fork a new worker at the given index, returning the
|
|
@@ -530,19 +541,20 @@ module Raptor
|
|
|
530
541
|
#
|
|
531
542
|
# @rbs (Integer pid, Process::Status status) -> void
|
|
532
543
|
def reap_pid(pid, status)
|
|
544
|
+
index = @worker_indices.delete(pid)
|
|
545
|
+
return unless index
|
|
546
|
+
|
|
547
|
+
active = @workers[index] == pid
|
|
533
548
|
if pid == @seed_pid
|
|
534
549
|
Log.info "Seed (#{pid}) exited, #{exit_description(status)}"
|
|
535
550
|
@seed_pid = nil
|
|
536
|
-
return
|
|
537
551
|
end
|
|
538
552
|
|
|
539
|
-
|
|
540
|
-
return unless index
|
|
541
|
-
|
|
542
|
-
@workers.delete(index)
|
|
553
|
+
@workers.delete(index) if active
|
|
543
554
|
@timed_out.delete(pid)
|
|
555
|
+
@after_worker_exit.each { |hook| hook.parameters.empty? ? hook.call : hook.call(index, pid, status) }
|
|
544
556
|
|
|
545
|
-
|
|
557
|
+
if active && !@shutdown
|
|
546
558
|
Log.warn "Restarting worker #{index} (#{pid}), #{exit_description(status)}"
|
|
547
559
|
spawn_worker(index)
|
|
548
560
|
end
|
|
@@ -674,7 +686,11 @@ module Raptor
|
|
|
674
686
|
pids = @workers.values + [@seed_pid].compact
|
|
675
687
|
Log.warn "Force-killing #{pids.size} process(es) after #{@worker_shutdown_timeout}s"
|
|
676
688
|
pids.each { |pid| Process.kill("KILL", pid) rescue nil }
|
|
677
|
-
pids.each
|
|
689
|
+
pids.each do |pid|
|
|
690
|
+
_, status = Process.wait2(pid)
|
|
691
|
+
reap_pid(pid, status)
|
|
692
|
+
rescue Errno::ECHILD
|
|
693
|
+
end
|
|
678
694
|
end
|
|
679
695
|
|
|
680
696
|
# Kills workers that have stopped checking in. A booted worker that
|
|
@@ -850,7 +866,6 @@ module Raptor
|
|
|
850
866
|
CPU.pin(index) if @cpu_affinity && CPU.count >= @worker_count
|
|
851
867
|
|
|
852
868
|
started_at = Process.clock_gettime(Process::CLOCK_REALTIME)
|
|
853
|
-
request_count = 0
|
|
854
869
|
|
|
855
870
|
@stats.write(
|
|
856
871
|
index,
|
|
@@ -867,70 +882,6 @@ module Raptor
|
|
|
867
882
|
|
|
868
883
|
@before_worker_boot.each { |hook| hook.parameters.empty? ? hook.call : hook.call(index) }
|
|
869
884
|
|
|
870
|
-
reactor = nil
|
|
871
|
-
|
|
872
|
-
counting_app = ->(env) {
|
|
873
|
-
request_count += 1
|
|
874
|
-
@app.call(env)
|
|
875
|
-
}
|
|
876
|
-
thread_pool = AtomicThreadPool.new(size: @thread_count, max_size: @max_thread_count)
|
|
877
|
-
http1 = Http1.new(
|
|
878
|
-
counting_app,
|
|
879
|
-
@server_port,
|
|
880
|
-
connection_options: @connection_options,
|
|
881
|
-
http1_options: @http1_options,
|
|
882
|
-
access_log_io: @access_log_io,
|
|
883
|
-
clean_thread_locals: @clean_thread_locals,
|
|
884
|
-
clean_fiber_locals: @clean_fiber_locals,
|
|
885
|
-
on_error: @on_error
|
|
886
|
-
)
|
|
887
|
-
http2 = Http2.new(
|
|
888
|
-
counting_app,
|
|
889
|
-
@server_port,
|
|
890
|
-
connection_options: @connection_options,
|
|
891
|
-
http2_options: @http2_options,
|
|
892
|
-
access_log_io: @access_log_io,
|
|
893
|
-
clean_thread_locals: @clean_thread_locals,
|
|
894
|
-
clean_fiber_locals: @clean_fiber_locals,
|
|
895
|
-
on_error: @on_error
|
|
896
|
-
)
|
|
897
|
-
http1_ractor_pool = RactorPool.new(
|
|
898
|
-
size: @http1_ractor_count,
|
|
899
|
-
worker: http1.parser_worker,
|
|
900
|
-
name: "HTTP/1.1"
|
|
901
|
-
) do |parsed_result|
|
|
902
|
-
begin
|
|
903
|
-
http1.handle_parsed_request(parsed_result, reactor, thread_pool)
|
|
904
|
-
rescue => error
|
|
905
|
-
Log.rescued_error(error)
|
|
906
|
-
end
|
|
907
|
-
end
|
|
908
|
-
|
|
909
|
-
http2_ractor_pool = if @binder.http2?
|
|
910
|
-
RactorPool.new(
|
|
911
|
-
size: @http2_ractor_count,
|
|
912
|
-
worker: http2.parser_worker,
|
|
913
|
-
name: "HTTP/2"
|
|
914
|
-
) do |parsed_result|
|
|
915
|
-
begin
|
|
916
|
-
http2.handle_parsed_request(parsed_result, reactor, thread_pool)
|
|
917
|
-
rescue => error
|
|
918
|
-
Log.rescued_error(error)
|
|
919
|
-
end
|
|
920
|
-
end
|
|
921
|
-
end
|
|
922
|
-
|
|
923
|
-
reactor = Reactor.new(
|
|
924
|
-
http1,
|
|
925
|
-
http1_ractor_pool,
|
|
926
|
-
http2_ractor_pool,
|
|
927
|
-
thread_pool,
|
|
928
|
-
connection_options: @connection_options,
|
|
929
|
-
http1_options: @http1_options,
|
|
930
|
-
http2_options: @http2_options
|
|
931
|
-
)
|
|
932
|
-
reactor_thread = reactor.run
|
|
933
|
-
|
|
934
885
|
bpf_listeners = if @bpf_active
|
|
935
886
|
ReuseportBPF.enable_load_reporting(index)
|
|
936
887
|
ReuseportBPF.create_worker_listeners(index, @binder.socket_backlog)
|
|
@@ -938,17 +889,17 @@ module Raptor
|
|
|
938
889
|
[]
|
|
939
890
|
end
|
|
940
891
|
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
thread_pool,
|
|
944
|
-
http1,
|
|
945
|
-
http2,
|
|
946
|
-
connection_options: @connection_options,
|
|
947
|
-
drain_accept_queue: @drain_accept_queue,
|
|
892
|
+
worker = Worker.new(
|
|
893
|
+
@app,
|
|
948
894
|
listeners: bpf_listeners + @binder.listeners,
|
|
895
|
+
port: @server_port,
|
|
896
|
+
options: @options,
|
|
897
|
+
http1_ractors: @http1_ractor_count,
|
|
898
|
+
http2_ractors: @http2_ractor_count,
|
|
899
|
+
access_log_io: @access_log_io,
|
|
949
900
|
worker_index: (index if @bpf_active)
|
|
950
901
|
)
|
|
951
|
-
|
|
902
|
+
worker.start
|
|
952
903
|
|
|
953
904
|
Log.info "Worker #{index} booted"
|
|
954
905
|
|
|
@@ -960,10 +911,10 @@ module Raptor
|
|
|
960
911
|
index,
|
|
961
912
|
pid: Process.pid,
|
|
962
913
|
phase: phase,
|
|
963
|
-
requests:
|
|
964
|
-
backlog: reactor.backlog,
|
|
965
|
-
busy_threads: thread_pool.active_count,
|
|
966
|
-
thread_capacity: thread_pool.size,
|
|
914
|
+
requests: worker.requests,
|
|
915
|
+
backlog: worker.reactor.backlog,
|
|
916
|
+
busy_threads: worker.thread_pool.active_count,
|
|
917
|
+
thread_capacity: worker.thread_pool.size,
|
|
967
918
|
started_at: started_at,
|
|
968
919
|
last_checkin: Process.clock_gettime(Process::CLOCK_REALTIME),
|
|
969
920
|
booted: true
|
|
@@ -975,30 +926,21 @@ module Raptor
|
|
|
975
926
|
end
|
|
976
927
|
|
|
977
928
|
until shutdown_requested || promote_to_seed
|
|
978
|
-
break unless
|
|
929
|
+
break unless worker.running?
|
|
979
930
|
|
|
980
931
|
sleep 0.5
|
|
981
932
|
end
|
|
982
933
|
|
|
983
934
|
if promote_to_seed
|
|
984
935
|
@before_refork.each(&:call)
|
|
985
|
-
server.stop_accepting
|
|
986
936
|
else
|
|
987
937
|
@before_worker_shutdown.each { |hook| hook.parameters.empty? ? hook.call : hook.call(index) }
|
|
988
|
-
server.shutdown
|
|
989
938
|
end
|
|
990
939
|
|
|
991
|
-
|
|
940
|
+
worker.shutdown(close_listeners: !promote_to_seed)
|
|
941
|
+
@after_worker_drain.each { |hook| hook.parameters.empty? ? hook.call : hook.call(index) }
|
|
992
942
|
# A seed never accepts again, and the workers it forks bind their own.
|
|
993
943
|
bpf_listeners.each(&:close) if promote_to_seed
|
|
994
|
-
http1.shutdown
|
|
995
|
-
http2.shutdown(reactor)
|
|
996
|
-
reactor.drain_detached_bodies(@worker_drain_timeout)
|
|
997
|
-
drain_thread_pool(thread_pool)
|
|
998
|
-
reactor.shutdown
|
|
999
|
-
reactor_thread.join
|
|
1000
|
-
http1_ractor_pool.shutdown
|
|
1001
|
-
http2_ractor_pool&.shutdown
|
|
1002
944
|
stats_thread.join
|
|
1003
945
|
|
|
1004
946
|
run_seed_loop(index) if promote_to_seed
|
|
@@ -1041,27 +983,6 @@ module Raptor
|
|
|
1041
983
|
rescue Errno::EPIPE, IOError
|
|
1042
984
|
end
|
|
1043
985
|
|
|
1044
|
-
# Shuts down the worker's application thread pool, force-killing the
|
|
1045
|
-
# underlying threads if in-flight requests have not finished within
|
|
1046
|
-
# `worker_drain_timeout` seconds.
|
|
1047
|
-
#
|
|
1048
|
-
# @param thread_pool [AtomicThreadPool] the worker's thread pool
|
|
1049
|
-
# @return [void]
|
|
1050
|
-
#
|
|
1051
|
-
# @rbs (AtomicThreadPool thread_pool) -> void
|
|
1052
|
-
def drain_thread_pool(thread_pool)
|
|
1053
|
-
drain_thread = Thread.new do
|
|
1054
|
-
Thread.current.name = "Thread Pool Drain"
|
|
1055
|
-
|
|
1056
|
-
thread_pool.shutdown
|
|
1057
|
-
end
|
|
1058
|
-
return if drain_thread.join(@worker_drain_timeout)
|
|
1059
|
-
|
|
1060
|
-
Log.warn "Force-killing in-flight app threads after #{@worker_drain_timeout}s drain timeout"
|
|
1061
|
-
thread_pool.instance_variable_get(:@threads).each(&:kill)
|
|
1062
|
-
drain_thread.join
|
|
1063
|
-
end
|
|
1064
|
-
|
|
1065
986
|
# Returns a human-readable description of how a process exited.
|
|
1066
987
|
#
|
|
1067
988
|
# @param status [Process::Status] the exit status of the process
|