jun-puma 1.0.1-java → 1.0.2-java
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/lib/puma/puma_http11.jar +0 -0
- metadata +3 -81
- data/bin/puma-wild +0 -25
- data/docs/architecture.md +0 -74
- data/docs/compile_options.md +0 -55
- data/docs/deployment.md +0 -102
- data/docs/fork_worker.md +0 -31
- data/docs/images/puma-connection-flow-no-reactor.png +0 -0
- data/docs/images/puma-connection-flow.png +0 -0
- data/docs/images/puma-general-arch.png +0 -0
- data/docs/jungle/README.md +0 -9
- data/docs/jungle/rc.d/README.md +0 -74
- data/docs/jungle/rc.d/puma +0 -61
- data/docs/jungle/rc.d/puma.conf +0 -10
- data/docs/kubernetes.md +0 -78
- data/docs/nginx.md +0 -80
- data/docs/plugins.md +0 -38
- data/docs/rails_dev_mode.md +0 -28
- data/docs/restart.md +0 -64
- data/docs/signals.md +0 -98
- data/docs/stats.md +0 -142
- data/docs/systemd.md +0 -244
- data/docs/testing_benchmarks_local_files.md +0 -150
- data/docs/testing_test_rackup_ci_files.md +0 -36
- data/ext/puma_http11/PumaHttp11Service.java +0 -17
- data/ext/puma_http11/ext_help.h +0 -15
- data/ext/puma_http11/http11_parser.c +0 -1057
- data/ext/puma_http11/http11_parser.h +0 -65
- data/ext/puma_http11/http11_parser.java.rl +0 -145
- data/ext/puma_http11/http11_parser.rl +0 -149
- data/ext/puma_http11/http11_parser_common.rl +0 -54
- data/ext/puma_http11/mini_ssl.c +0 -832
- data/ext/puma_http11/no_ssl/PumaHttp11Service.java +0 -15
- data/ext/puma_http11/org/jruby/puma/Http11.java +0 -226
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +0 -455
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +0 -508
- data/ext/puma_http11/puma_http11.c +0 -492
- data/lib/puma/app/status.rb +0 -96
- data/lib/puma/binder.rb +0 -501
- data/lib/puma/cli.rb +0 -243
- data/lib/puma/client.rb +0 -632
- data/lib/puma/cluster/worker.rb +0 -182
- data/lib/puma/cluster/worker_handle.rb +0 -97
- data/lib/puma/cluster.rb +0 -562
- data/lib/puma/commonlogger.rb +0 -115
- data/lib/puma/configuration.rb +0 -391
- data/lib/puma/const.rb +0 -289
- data/lib/puma/control_cli.rb +0 -316
- data/lib/puma/detect.rb +0 -45
- data/lib/puma/dsl.rb +0 -1204
- data/lib/puma/error_logger.rb +0 -113
- data/lib/puma/events.rb +0 -57
- data/lib/puma/io_buffer.rb +0 -46
- data/lib/puma/jruby_restart.rb +0 -27
- data/lib/puma/json_serialization.rb +0 -96
- data/lib/puma/launcher/bundle_pruner.rb +0 -104
- data/lib/puma/launcher.rb +0 -484
- data/lib/puma/log_writer.rb +0 -147
- data/lib/puma/minissl/context_builder.rb +0 -95
- data/lib/puma/minissl.rb +0 -458
- data/lib/puma/null_io.rb +0 -61
- data/lib/puma/plugin/systemd.rb +0 -90
- data/lib/puma/plugin/tmp_restart.rb +0 -36
- data/lib/puma/plugin.rb +0 -111
- data/lib/puma/rack/builder.rb +0 -297
- data/lib/puma/rack/urlmap.rb +0 -93
- data/lib/puma/rack_default.rb +0 -24
- data/lib/puma/reactor.rb +0 -125
- data/lib/puma/request.rb +0 -671
- data/lib/puma/runner.rb +0 -213
- data/lib/puma/sd_notify.rb +0 -149
- data/lib/puma/server.rb +0 -664
- data/lib/puma/single.rb +0 -69
- data/lib/puma/state_file.rb +0 -68
- data/lib/puma/thread_pool.rb +0 -434
- data/lib/puma/util.rb +0 -141
- data/lib/puma.rb +0 -78
- data/lib/rack/handler/puma.rb +0 -141
- data/tools/Dockerfile +0 -16
- data/tools/trickletest.rb +0 -44
data/lib/puma/single.rb
DELETED
@@ -1,69 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative 'runner'
|
4
|
-
require_relative 'detect'
|
5
|
-
require_relative 'plugin'
|
6
|
-
|
7
|
-
module Puma
|
8
|
-
# This class is instantiated by the `Puma::Launcher` and used
|
9
|
-
# to boot and serve a Ruby application when no puma "workers" are needed
|
10
|
-
# i.e. only using "threaded" mode. For example `$ puma -t 1:5`
|
11
|
-
#
|
12
|
-
# At the core of this class is running an instance of `Puma::Server` which
|
13
|
-
# gets created via the `start_server` method from the `Puma::Runner` class
|
14
|
-
# that this inherits from.
|
15
|
-
class Single < Runner
|
16
|
-
# @!attribute [r] stats
|
17
|
-
def stats
|
18
|
-
{
|
19
|
-
started_at: utc_iso8601(@started_at)
|
20
|
-
}.merge(@server.stats).merge(super)
|
21
|
-
end
|
22
|
-
|
23
|
-
def restart
|
24
|
-
@server&.begin_restart
|
25
|
-
end
|
26
|
-
|
27
|
-
def stop
|
28
|
-
@server&.stop false
|
29
|
-
end
|
30
|
-
|
31
|
-
def halt
|
32
|
-
@server&.halt
|
33
|
-
end
|
34
|
-
|
35
|
-
def stop_blocked
|
36
|
-
log "- Gracefully stopping, waiting for requests to finish"
|
37
|
-
@control&.stop true
|
38
|
-
@server&.stop true
|
39
|
-
end
|
40
|
-
|
41
|
-
def run
|
42
|
-
output_header "single"
|
43
|
-
|
44
|
-
load_and_bind
|
45
|
-
|
46
|
-
Plugins.fire_background
|
47
|
-
|
48
|
-
@launcher.write_state
|
49
|
-
|
50
|
-
start_control
|
51
|
-
|
52
|
-
@server = server = start_server
|
53
|
-
server_thread = server.run
|
54
|
-
|
55
|
-
log "Use Ctrl-C to stop"
|
56
|
-
redirect_io
|
57
|
-
|
58
|
-
@events.fire_on_booted!
|
59
|
-
|
60
|
-
debug_loaded_extensions("Loaded Extensions:") if @log_writer.debug?
|
61
|
-
|
62
|
-
begin
|
63
|
-
server_thread.join
|
64
|
-
rescue Interrupt
|
65
|
-
# Swallow it
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
data/lib/puma/state_file.rb
DELETED
@@ -1,68 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Puma
|
4
|
-
|
5
|
-
# Puma::Launcher uses StateFile to write a yaml file for use with Puma::ControlCLI.
|
6
|
-
#
|
7
|
-
# In previous versions of Puma, YAML was used to read/write the state file.
|
8
|
-
# Since Puma is similar to Bundler/RubyGems in that it may load before one's app
|
9
|
-
# does, minimizing the dependencies that may be shared with the app is desired.
|
10
|
-
#
|
11
|
-
# At present, it only works with numeric and string values. It is still a valid
|
12
|
-
# yaml file, and the CI tests parse it with Psych.
|
13
|
-
#
|
14
|
-
class StateFile
|
15
|
-
|
16
|
-
ALLOWED_FIELDS = %w!control_url control_auth_token pid running_from!
|
17
|
-
|
18
|
-
def initialize
|
19
|
-
@options = {}
|
20
|
-
end
|
21
|
-
|
22
|
-
def save(path, permission = nil)
|
23
|
-
contents = +"---\n"
|
24
|
-
@options.each do |k,v|
|
25
|
-
next unless ALLOWED_FIELDS.include? k
|
26
|
-
case v
|
27
|
-
when Numeric
|
28
|
-
contents << "#{k}: #{v}\n"
|
29
|
-
when String
|
30
|
-
next if v.strip.empty?
|
31
|
-
contents << (k == 'running_from' || v.to_s.include?(' ') ?
|
32
|
-
"#{k}: \"#{v}\"\n" : "#{k}: #{v}\n")
|
33
|
-
end
|
34
|
-
end
|
35
|
-
if permission
|
36
|
-
File.write path, contents, mode: 'wb:UTF-8'
|
37
|
-
else
|
38
|
-
File.write path, contents, mode: 'wb:UTF-8', perm: permission
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def load(path)
|
43
|
-
File.read(path).lines.each do |line|
|
44
|
-
next if line.start_with? '#'
|
45
|
-
k,v = line.split ':', 2
|
46
|
-
next unless v && ALLOWED_FIELDS.include?(k)
|
47
|
-
v = v.strip
|
48
|
-
@options[k] =
|
49
|
-
case v
|
50
|
-
when '' then nil
|
51
|
-
when /\A\d+\z/ then v.to_i
|
52
|
-
when /\A\d+\.\d+\z/ then v.to_f
|
53
|
-
else v.gsub(/\A"|"\z/, '')
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
ALLOWED_FIELDS.each do |f|
|
59
|
-
define_method f do
|
60
|
-
@options[f]
|
61
|
-
end
|
62
|
-
|
63
|
-
define_method "#{f}=" do |v|
|
64
|
-
@options[f] = v
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
data/lib/puma/thread_pool.rb
DELETED
@@ -1,434 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'thread'
|
4
|
-
|
5
|
-
require_relative 'io_buffer'
|
6
|
-
|
7
|
-
module Puma
|
8
|
-
# Internal Docs for A simple thread pool management object.
|
9
|
-
#
|
10
|
-
# Each Puma "worker" has a thread pool to process requests.
|
11
|
-
#
|
12
|
-
# First a connection to a client is made in `Puma::Server`. It is wrapped in a
|
13
|
-
# `Puma::Client` instance and then passed to the `Puma::Reactor` to ensure
|
14
|
-
# the whole request is buffered into memory. Once the request is ready, it is passed into
|
15
|
-
# a thread pool via the `Puma::ThreadPool#<<` operator where it is stored in a `@todo` array.
|
16
|
-
#
|
17
|
-
# Each thread in the pool has an internal loop where it pulls a request from the `@todo` array
|
18
|
-
# and processes it.
|
19
|
-
class ThreadPool
|
20
|
-
class ForceShutdown < RuntimeError
|
21
|
-
end
|
22
|
-
|
23
|
-
# How long, after raising the ForceShutdown of a thread during
|
24
|
-
# forced shutdown mode, to wait for the thread to try and finish
|
25
|
-
# up its work before leaving the thread to die on the vine.
|
26
|
-
SHUTDOWN_GRACE_TIME = 5 # seconds
|
27
|
-
|
28
|
-
# Maintain a minimum of +min+ and maximum of +max+ threads
|
29
|
-
# in the pool.
|
30
|
-
#
|
31
|
-
# The block passed is the work that will be performed in each
|
32
|
-
# thread.
|
33
|
-
#
|
34
|
-
def initialize(name, options = {}, &block)
|
35
|
-
@not_empty = ConditionVariable.new
|
36
|
-
@not_full = ConditionVariable.new
|
37
|
-
@mutex = Mutex.new
|
38
|
-
|
39
|
-
@todo = []
|
40
|
-
|
41
|
-
@spawned = 0
|
42
|
-
@waiting = 0
|
43
|
-
|
44
|
-
@name = name
|
45
|
-
@min = Integer(options[:min_threads])
|
46
|
-
@max = Integer(options[:max_threads])
|
47
|
-
# Not an 'exposed' option, options[:pool_shutdown_grace_time] is used in CI
|
48
|
-
# to shorten @shutdown_grace_time from SHUTDOWN_GRACE_TIME. Parallel CI
|
49
|
-
# makes stubbing constants difficult.
|
50
|
-
@shutdown_grace_time = Float(options[:pool_shutdown_grace_time] || SHUTDOWN_GRACE_TIME)
|
51
|
-
@block = block
|
52
|
-
@out_of_band = options[:out_of_band]
|
53
|
-
@clean_thread_locals = options[:clean_thread_locals]
|
54
|
-
@before_thread_start = options[:before_thread_start]
|
55
|
-
@before_thread_exit = options[:before_thread_exit]
|
56
|
-
@reaping_time = options[:reaping_time]
|
57
|
-
@auto_trim_time = options[:auto_trim_time]
|
58
|
-
|
59
|
-
@shutdown = false
|
60
|
-
|
61
|
-
@trim_requested = 0
|
62
|
-
@out_of_band_pending = false
|
63
|
-
|
64
|
-
@workers = []
|
65
|
-
|
66
|
-
@auto_trim = nil
|
67
|
-
@reaper = nil
|
68
|
-
|
69
|
-
@mutex.synchronize do
|
70
|
-
@min.times do
|
71
|
-
spawn_thread
|
72
|
-
@not_full.wait(@mutex)
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
@force_shutdown = false
|
77
|
-
@shutdown_mutex = Mutex.new
|
78
|
-
end
|
79
|
-
|
80
|
-
attr_reader :spawned, :trim_requested, :waiting
|
81
|
-
|
82
|
-
def self.clean_thread_locals
|
83
|
-
Thread.current.keys.each do |key| # rubocop: disable Style/HashEachMethods
|
84
|
-
Thread.current[key] = nil unless key == :__recursive_key__
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
# How many objects have yet to be processed by the pool?
|
89
|
-
#
|
90
|
-
def backlog
|
91
|
-
with_mutex { @todo.size }
|
92
|
-
end
|
93
|
-
|
94
|
-
# @!attribute [r] pool_capacity
|
95
|
-
def pool_capacity
|
96
|
-
waiting + (@max - spawned)
|
97
|
-
end
|
98
|
-
|
99
|
-
# @!attribute [r] busy_threads
|
100
|
-
# @version 5.0.0
|
101
|
-
def busy_threads
|
102
|
-
with_mutex { @spawned - @waiting + @todo.size }
|
103
|
-
end
|
104
|
-
|
105
|
-
# :nodoc:
|
106
|
-
#
|
107
|
-
# Must be called with @mutex held!
|
108
|
-
#
|
109
|
-
def spawn_thread
|
110
|
-
@spawned += 1
|
111
|
-
|
112
|
-
trigger_before_thread_start_hooks
|
113
|
-
th = Thread.new(@spawned) do |spawned|
|
114
|
-
Puma.set_thread_name '%s tp %03i' % [@name, spawned]
|
115
|
-
todo = @todo
|
116
|
-
block = @block
|
117
|
-
mutex = @mutex
|
118
|
-
not_empty = @not_empty
|
119
|
-
not_full = @not_full
|
120
|
-
|
121
|
-
while true
|
122
|
-
work = nil
|
123
|
-
|
124
|
-
mutex.synchronize do
|
125
|
-
while todo.empty?
|
126
|
-
if @trim_requested > 0
|
127
|
-
@trim_requested -= 1
|
128
|
-
@spawned -= 1
|
129
|
-
@workers.delete th
|
130
|
-
not_full.signal
|
131
|
-
trigger_before_thread_exit_hooks
|
132
|
-
Thread.exit
|
133
|
-
end
|
134
|
-
|
135
|
-
@waiting += 1
|
136
|
-
if @out_of_band_pending && trigger_out_of_band_hook
|
137
|
-
@out_of_band_pending = false
|
138
|
-
end
|
139
|
-
not_full.signal
|
140
|
-
begin
|
141
|
-
not_empty.wait mutex
|
142
|
-
ensure
|
143
|
-
@waiting -= 1
|
144
|
-
end
|
145
|
-
end
|
146
|
-
|
147
|
-
work = todo.shift
|
148
|
-
end
|
149
|
-
|
150
|
-
if @clean_thread_locals
|
151
|
-
ThreadPool.clean_thread_locals
|
152
|
-
end
|
153
|
-
|
154
|
-
begin
|
155
|
-
@out_of_band_pending = true if block.call(work)
|
156
|
-
rescue Exception => e
|
157
|
-
STDERR.puts "Error reached top of thread-pool: #{e.message} (#{e.class})"
|
158
|
-
end
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
|
-
@workers << th
|
163
|
-
|
164
|
-
th
|
165
|
-
end
|
166
|
-
|
167
|
-
private :spawn_thread
|
168
|
-
|
169
|
-
def trigger_before_thread_start_hooks
|
170
|
-
return unless @before_thread_start&.any?
|
171
|
-
|
172
|
-
@before_thread_start.each do |b|
|
173
|
-
begin
|
174
|
-
b.call
|
175
|
-
rescue Exception => e
|
176
|
-
STDERR.puts "WARNING before_thread_start hook failed with exception (#{e.class}) #{e.message}"
|
177
|
-
end
|
178
|
-
end
|
179
|
-
nil
|
180
|
-
end
|
181
|
-
|
182
|
-
private :trigger_before_thread_start_hooks
|
183
|
-
|
184
|
-
def trigger_before_thread_exit_hooks
|
185
|
-
return unless @before_thread_exit&.any?
|
186
|
-
|
187
|
-
@before_thread_exit.each do |b|
|
188
|
-
begin
|
189
|
-
b.call
|
190
|
-
rescue Exception => e
|
191
|
-
STDERR.puts "WARNING before_thread_exit hook failed with exception (#{e.class}) #{e.message}"
|
192
|
-
end
|
193
|
-
end
|
194
|
-
nil
|
195
|
-
end
|
196
|
-
|
197
|
-
private :trigger_before_thread_exit_hooks
|
198
|
-
|
199
|
-
# @version 5.0.0
|
200
|
-
def trigger_out_of_band_hook
|
201
|
-
return false unless @out_of_band&.any?
|
202
|
-
|
203
|
-
# we execute on idle hook when all threads are free
|
204
|
-
return false unless @spawned == @waiting
|
205
|
-
|
206
|
-
@out_of_band.each(&:call)
|
207
|
-
true
|
208
|
-
rescue Exception => e
|
209
|
-
STDERR.puts "Exception calling out_of_band_hook: #{e.message} (#{e.class})"
|
210
|
-
true
|
211
|
-
end
|
212
|
-
|
213
|
-
private :trigger_out_of_band_hook
|
214
|
-
|
215
|
-
# @version 5.0.0
|
216
|
-
def with_mutex(&block)
|
217
|
-
@mutex.owned? ?
|
218
|
-
yield :
|
219
|
-
@mutex.synchronize(&block)
|
220
|
-
end
|
221
|
-
|
222
|
-
# Add +work+ to the todo list for a Thread to pickup and process.
|
223
|
-
def <<(work)
|
224
|
-
with_mutex do
|
225
|
-
if @shutdown
|
226
|
-
raise "Unable to add work while shutting down"
|
227
|
-
end
|
228
|
-
|
229
|
-
@todo << work
|
230
|
-
|
231
|
-
if @waiting < @todo.size and @spawned < @max
|
232
|
-
spawn_thread
|
233
|
-
end
|
234
|
-
|
235
|
-
@not_empty.signal
|
236
|
-
end
|
237
|
-
end
|
238
|
-
|
239
|
-
# This method is used by `Puma::Server` to let the server know when
|
240
|
-
# the thread pool can pull more requests from the socket and
|
241
|
-
# pass to the reactor.
|
242
|
-
#
|
243
|
-
# The general idea is that the thread pool can only work on a fixed
|
244
|
-
# number of requests at the same time. If it is already processing that
|
245
|
-
# number of requests then it is at capacity. If another Puma process has
|
246
|
-
# spare capacity, then the request can be left on the socket so the other
|
247
|
-
# worker can pick it up and process it.
|
248
|
-
#
|
249
|
-
# For example: if there are 5 threads, but only 4 working on
|
250
|
-
# requests, this method will not wait and the `Puma::Server`
|
251
|
-
# can pull a request right away.
|
252
|
-
#
|
253
|
-
# If there are 5 threads and all 5 of them are busy, then it will
|
254
|
-
# pause here, and wait until the `not_full` condition variable is
|
255
|
-
# signaled, usually this indicates that a request has been processed.
|
256
|
-
#
|
257
|
-
# It's important to note that even though the server might accept another
|
258
|
-
# request, it might not be added to the `@todo` array right away.
|
259
|
-
# For example if a slow client has only sent a header, but not a body
|
260
|
-
# then the `@todo` array would stay the same size as the reactor works
|
261
|
-
# to try to buffer the request. In that scenario the next call to this
|
262
|
-
# method would not block and another request would be added into the reactor
|
263
|
-
# by the server. This would continue until a fully buffered request
|
264
|
-
# makes it through the reactor and can then be processed by the thread pool.
|
265
|
-
def wait_until_not_full
|
266
|
-
with_mutex do
|
267
|
-
while true
|
268
|
-
return if @shutdown
|
269
|
-
|
270
|
-
# If we can still spin up new threads and there
|
271
|
-
# is work queued that cannot be handled by waiting
|
272
|
-
# threads, then accept more work until we would
|
273
|
-
# spin up the max number of threads.
|
274
|
-
return if busy_threads < @max
|
275
|
-
|
276
|
-
@not_full.wait @mutex
|
277
|
-
end
|
278
|
-
end
|
279
|
-
end
|
280
|
-
|
281
|
-
# @version 5.0.0
|
282
|
-
def wait_for_less_busy_worker(delay_s)
|
283
|
-
return unless delay_s && delay_s > 0
|
284
|
-
|
285
|
-
# Ruby MRI does GVL, this can result
|
286
|
-
# in processing contention when multiple threads
|
287
|
-
# (requests) are running concurrently
|
288
|
-
return unless Puma.mri?
|
289
|
-
|
290
|
-
with_mutex do
|
291
|
-
return if @shutdown
|
292
|
-
|
293
|
-
# do not delay, if we are not busy
|
294
|
-
return unless busy_threads > 0
|
295
|
-
|
296
|
-
# this will be signaled once a request finishes,
|
297
|
-
# which can happen earlier than delay
|
298
|
-
@not_full.wait @mutex, delay_s
|
299
|
-
end
|
300
|
-
end
|
301
|
-
|
302
|
-
# If there are any free threads in the pool, tell one to go ahead
|
303
|
-
# and exit. If +force+ is true, then a trim request is requested
|
304
|
-
# even if all threads are being utilized.
|
305
|
-
#
|
306
|
-
def trim(force=false)
|
307
|
-
with_mutex do
|
308
|
-
free = @waiting - @todo.size
|
309
|
-
if (force or free > 0) and @spawned - @trim_requested > @min
|
310
|
-
@trim_requested += 1
|
311
|
-
@not_empty.signal
|
312
|
-
end
|
313
|
-
end
|
314
|
-
end
|
315
|
-
|
316
|
-
# If there are dead threads in the pool make them go away while decreasing
|
317
|
-
# spawned counter so that new healthy threads could be created again.
|
318
|
-
def reap
|
319
|
-
with_mutex do
|
320
|
-
dead_workers = @workers.reject(&:alive?)
|
321
|
-
|
322
|
-
dead_workers.each do |worker|
|
323
|
-
worker.kill
|
324
|
-
@spawned -= 1
|
325
|
-
end
|
326
|
-
|
327
|
-
@workers.delete_if do |w|
|
328
|
-
dead_workers.include?(w)
|
329
|
-
end
|
330
|
-
end
|
331
|
-
end
|
332
|
-
|
333
|
-
class Automaton
|
334
|
-
def initialize(pool, timeout, thread_name, message)
|
335
|
-
@pool = pool
|
336
|
-
@timeout = timeout
|
337
|
-
@thread_name = thread_name
|
338
|
-
@message = message
|
339
|
-
@running = false
|
340
|
-
end
|
341
|
-
|
342
|
-
def start!
|
343
|
-
@running = true
|
344
|
-
|
345
|
-
@thread = Thread.new do
|
346
|
-
Puma.set_thread_name @thread_name
|
347
|
-
while @running
|
348
|
-
@pool.public_send(@message)
|
349
|
-
sleep @timeout
|
350
|
-
end
|
351
|
-
end
|
352
|
-
end
|
353
|
-
|
354
|
-
def stop
|
355
|
-
@running = false
|
356
|
-
@thread.wakeup
|
357
|
-
end
|
358
|
-
end
|
359
|
-
|
360
|
-
def auto_trim!(timeout=@auto_trim_time)
|
361
|
-
@auto_trim = Automaton.new(self, timeout, "#{@name} threadpool trimmer", :trim)
|
362
|
-
@auto_trim.start!
|
363
|
-
end
|
364
|
-
|
365
|
-
def auto_reap!(timeout=@reaping_time)
|
366
|
-
@reaper = Automaton.new(self, timeout, "#{@name} threadpool reaper", :reap)
|
367
|
-
@reaper.start!
|
368
|
-
end
|
369
|
-
|
370
|
-
# Allows ThreadPool::ForceShutdown to be raised within the
|
371
|
-
# provided block if the thread is forced to shutdown during execution.
|
372
|
-
def with_force_shutdown
|
373
|
-
t = Thread.current
|
374
|
-
@shutdown_mutex.synchronize do
|
375
|
-
raise ForceShutdown if @force_shutdown
|
376
|
-
t[:with_force_shutdown] = true
|
377
|
-
end
|
378
|
-
yield
|
379
|
-
ensure
|
380
|
-
t[:with_force_shutdown] = false
|
381
|
-
end
|
382
|
-
|
383
|
-
# Tell all threads in the pool to exit and wait for them to finish.
|
384
|
-
# Wait +timeout+ seconds then raise +ForceShutdown+ in remaining threads.
|
385
|
-
# Next, wait an extra +@shutdown_grace_time+ seconds then force-kill remaining
|
386
|
-
# threads. Finally, wait 1 second for remaining threads to exit.
|
387
|
-
#
|
388
|
-
def shutdown(timeout=-1)
|
389
|
-
threads = with_mutex do
|
390
|
-
@shutdown = true
|
391
|
-
@trim_requested = @spawned
|
392
|
-
@not_empty.broadcast
|
393
|
-
@not_full.broadcast
|
394
|
-
|
395
|
-
@auto_trim&.stop
|
396
|
-
@reaper&.stop
|
397
|
-
# dup workers so that we join them all safely
|
398
|
-
@workers.dup
|
399
|
-
end
|
400
|
-
|
401
|
-
if timeout == -1
|
402
|
-
# Wait for threads to finish without force shutdown.
|
403
|
-
threads.each(&:join)
|
404
|
-
else
|
405
|
-
join = ->(inner_timeout) do
|
406
|
-
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
407
|
-
threads.reject! do |t|
|
408
|
-
elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
|
409
|
-
t.join inner_timeout - elapsed
|
410
|
-
end
|
411
|
-
end
|
412
|
-
|
413
|
-
# Wait +timeout+ seconds for threads to finish.
|
414
|
-
join.call(timeout)
|
415
|
-
|
416
|
-
# If threads are still running, raise ForceShutdown and wait to finish.
|
417
|
-
@shutdown_mutex.synchronize do
|
418
|
-
@force_shutdown = true
|
419
|
-
threads.each do |t|
|
420
|
-
t.raise ForceShutdown if t[:with_force_shutdown]
|
421
|
-
end
|
422
|
-
end
|
423
|
-
join.call(@shutdown_grace_time)
|
424
|
-
|
425
|
-
# If threads are _still_ running, forcefully kill them and wait to finish.
|
426
|
-
threads.each(&:kill)
|
427
|
-
join.call(1)
|
428
|
-
end
|
429
|
-
|
430
|
-
@spawned = 0
|
431
|
-
@workers = []
|
432
|
-
end
|
433
|
-
end
|
434
|
-
end
|
data/lib/puma/util.rb
DELETED
@@ -1,141 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'uri/common'
|
4
|
-
|
5
|
-
module Puma
|
6
|
-
module Util
|
7
|
-
module_function
|
8
|
-
|
9
|
-
def pipe
|
10
|
-
IO.pipe
|
11
|
-
end
|
12
|
-
|
13
|
-
# An instance method on Thread has been provided to address https://bugs.ruby-lang.org/issues/13632,
|
14
|
-
# which currently effects some older versions of Ruby: 2.2.7 2.2.8 2.2.9 2.2.10 2.3.4 2.4.1
|
15
|
-
# Additional context: https://github.com/puma/puma/pull/1345
|
16
|
-
def purge_interrupt_queue
|
17
|
-
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
|
18
|
-
end
|
19
|
-
|
20
|
-
# Escapes and unescapes a URI escaped string with
|
21
|
-
# +encoding+. +encoding+ will be the target encoding of the string
|
22
|
-
# returned, and it defaults to UTF-8
|
23
|
-
if defined?(::Encoding)
|
24
|
-
def escape(s, encoding = Encoding::UTF_8)
|
25
|
-
URI.encode_www_form_component(s, encoding)
|
26
|
-
end
|
27
|
-
|
28
|
-
def unescape(s, encoding = Encoding::UTF_8)
|
29
|
-
URI.decode_www_form_component(s, encoding)
|
30
|
-
end
|
31
|
-
else
|
32
|
-
def escape(s, encoding = nil)
|
33
|
-
URI.encode_www_form_component(s, encoding)
|
34
|
-
end
|
35
|
-
|
36
|
-
def unescape(s, encoding = nil)
|
37
|
-
URI.decode_www_form_component(s, encoding)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
module_function :unescape, :escape
|
41
|
-
|
42
|
-
DEFAULT_SEP = /[&;] */n
|
43
|
-
|
44
|
-
# Stolen from Mongrel, with some small modifications:
|
45
|
-
# Parses a query string by breaking it up at the '&'
|
46
|
-
# and ';' characters. You can also use this to parse
|
47
|
-
# cookies by changing the characters used in the second
|
48
|
-
# parameter (which defaults to '&;').
|
49
|
-
def parse_query(qs, d = nil, &unescaper)
|
50
|
-
unescaper ||= method(:unescape)
|
51
|
-
|
52
|
-
params = {}
|
53
|
-
|
54
|
-
(qs || '').split(d ? /[#{d}] */n : DEFAULT_SEP).each do |p|
|
55
|
-
next if p.empty?
|
56
|
-
k, v = p.split('=', 2).map(&unescaper)
|
57
|
-
|
58
|
-
if cur = params[k]
|
59
|
-
if cur.class == Array
|
60
|
-
params[k] << v
|
61
|
-
else
|
62
|
-
params[k] = [cur, v]
|
63
|
-
end
|
64
|
-
else
|
65
|
-
params[k] = v
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
params
|
70
|
-
end
|
71
|
-
|
72
|
-
# A case-insensitive Hash that preserves the original case of a
|
73
|
-
# header when set.
|
74
|
-
class HeaderHash < Hash
|
75
|
-
def self.new(hash={})
|
76
|
-
HeaderHash === hash ? hash : super(hash)
|
77
|
-
end
|
78
|
-
|
79
|
-
def initialize(hash={})
|
80
|
-
super()
|
81
|
-
@names = {}
|
82
|
-
hash.each { |k, v| self[k] = v }
|
83
|
-
end
|
84
|
-
|
85
|
-
def each
|
86
|
-
super do |k, v|
|
87
|
-
yield(k, v.respond_to?(:to_ary) ? v.to_ary.join("\n") : v)
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
# @!attribute [r] to_hash
|
92
|
-
def to_hash
|
93
|
-
hash = {}
|
94
|
-
each { |k,v| hash[k] = v }
|
95
|
-
hash
|
96
|
-
end
|
97
|
-
|
98
|
-
def [](k)
|
99
|
-
super(k) || super(@names[k.downcase])
|
100
|
-
end
|
101
|
-
|
102
|
-
def []=(k, v)
|
103
|
-
canonical = k.downcase
|
104
|
-
delete k if @names[canonical] && @names[canonical] != k # .delete is expensive, don't invoke it unless necessary
|
105
|
-
@names[k] = @names[canonical] = k
|
106
|
-
super k, v
|
107
|
-
end
|
108
|
-
|
109
|
-
def delete(k)
|
110
|
-
canonical = k.downcase
|
111
|
-
result = super @names.delete(canonical)
|
112
|
-
@names.delete_if { |name,| name.downcase == canonical }
|
113
|
-
result
|
114
|
-
end
|
115
|
-
|
116
|
-
def include?(k)
|
117
|
-
@names.include?(k) || @names.include?(k.downcase)
|
118
|
-
end
|
119
|
-
|
120
|
-
alias_method :has_key?, :include?
|
121
|
-
alias_method :member?, :include?
|
122
|
-
alias_method :key?, :include?
|
123
|
-
|
124
|
-
def merge!(other)
|
125
|
-
other.each { |k, v| self[k] = v }
|
126
|
-
self
|
127
|
-
end
|
128
|
-
|
129
|
-
def merge(other)
|
130
|
-
hash = dup
|
131
|
-
hash.merge! other
|
132
|
-
end
|
133
|
-
|
134
|
-
def replace(other)
|
135
|
-
clear
|
136
|
-
other.each { |k, v| self[k] = v }
|
137
|
-
self
|
138
|
-
end
|
139
|
-
end
|
140
|
-
end
|
141
|
-
end
|