puma 4.3.1 → 5.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of puma might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/History.md +94 -3
- data/LICENSE +23 -20
- data/README.md +26 -13
- data/docs/architecture.md +3 -3
- data/docs/deployment.md +9 -3
- data/docs/fork_worker.md +31 -0
- data/docs/jungle/README.md +13 -0
- data/{tools → docs}/jungle/rc.d/README.md +0 -0
- data/{tools → docs}/jungle/rc.d/puma +0 -0
- data/{tools → docs}/jungle/rc.d/puma.conf +0 -0
- data/{tools → docs}/jungle/upstart/README.md +0 -0
- data/{tools → docs}/jungle/upstart/puma-manager.conf +0 -0
- data/{tools → docs}/jungle/upstart/puma.conf +0 -0
- data/docs/signals.md +7 -6
- data/docs/systemd.md +1 -63
- data/ext/puma_http11/PumaHttp11Service.java +2 -4
- data/ext/puma_http11/extconf.rb +4 -3
- data/ext/puma_http11/http11_parser.c +3 -1
- data/ext/puma_http11/http11_parser.rl +3 -1
- data/ext/puma_http11/mini_ssl.c +15 -2
- data/ext/puma_http11/no_ssl/PumaHttp11Service.java +15 -0
- data/ext/puma_http11/org/jruby/puma/Http11.java +3 -3
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +77 -18
- data/ext/puma_http11/puma_http11.c +7 -38
- data/lib/puma.rb +17 -0
- data/lib/puma/app/status.rb +18 -3
- data/lib/puma/binder.rb +88 -68
- data/lib/puma/cli.rb +7 -15
- data/lib/puma/client.rb +67 -14
- data/lib/puma/cluster.rb +191 -74
- data/lib/puma/commonlogger.rb +2 -2
- data/lib/puma/configuration.rb +31 -42
- data/lib/puma/const.rb +4 -3
- data/lib/puma/control_cli.rb +29 -17
- data/lib/puma/detect.rb +17 -0
- data/lib/puma/dsl.rb +144 -70
- data/lib/puma/error_logger.rb +97 -0
- data/lib/puma/events.rb +35 -31
- data/lib/puma/io_buffer.rb +9 -2
- data/lib/puma/jruby_restart.rb +0 -58
- data/lib/puma/launcher.rb +49 -31
- data/lib/puma/minissl.rb +60 -18
- data/lib/puma/minissl/context_builder.rb +0 -3
- data/lib/puma/null_io.rb +1 -1
- data/lib/puma/plugin.rb +1 -10
- data/lib/puma/rack/builder.rb +0 -4
- data/lib/puma/reactor.rb +9 -4
- data/lib/puma/runner.rb +8 -36
- data/lib/puma/server.rb +149 -186
- data/lib/puma/single.rb +7 -64
- data/lib/puma/state_file.rb +6 -3
- data/lib/puma/thread_pool.rb +94 -49
- data/lib/rack/handler/puma.rb +1 -3
- data/tools/{docker/Dockerfile → Dockerfile} +0 -0
- metadata +21 -23
- data/docs/tcp_mode.md +0 -96
- data/ext/puma_http11/io_buffer.c +0 -155
- data/ext/puma_http11/org/jruby/puma/IOBuffer.java +0 -72
- data/lib/puma/tcp_logger.rb +0 -41
- data/tools/jungle/README.md +0 -19
- data/tools/jungle/init.d/README.md +0 -61
- data/tools/jungle/init.d/puma +0 -421
- data/tools/jungle/init.d/run-puma +0 -18
data/lib/puma/single.rb
CHANGED
@@ -14,11 +14,9 @@ module Puma
|
|
14
14
|
# that this inherits from.
|
15
15
|
class Single < Runner
|
16
16
|
def stats
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
m = @server.max_threads || 0
|
21
|
-
%Q!{ "started_at": "#{@started_at.utc.iso8601}", "backlog": #{b}, "running": #{r}, "pool_capacity": #{t}, "max_threads": #{m} }!
|
17
|
+
{
|
18
|
+
started_at: @started_at.utc.iso8601
|
19
|
+
}.merge(@server.stats)
|
22
20
|
end
|
23
21
|
|
24
22
|
def restart
|
@@ -39,64 +37,10 @@ module Puma
|
|
39
37
|
@server.stop(true) if @server
|
40
38
|
end
|
41
39
|
|
42
|
-
def jruby_daemon?
|
43
|
-
daemon? and Puma.jruby?
|
44
|
-
end
|
45
|
-
|
46
|
-
def jruby_daemon_start
|
47
|
-
require 'puma/jruby_restart'
|
48
|
-
JRubyRestart.daemon_start(@restart_dir, @launcher.restart_args)
|
49
|
-
end
|
50
|
-
|
51
40
|
def run
|
52
|
-
already_daemon = false
|
53
|
-
|
54
|
-
if jruby_daemon?
|
55
|
-
require 'puma/jruby_restart'
|
56
|
-
|
57
|
-
if JRubyRestart.daemon?
|
58
|
-
# load and bind before redirecting IO so errors show up on stdout/stderr
|
59
|
-
load_and_bind
|
60
|
-
redirect_io
|
61
|
-
end
|
62
|
-
|
63
|
-
already_daemon = JRubyRestart.daemon_init
|
64
|
-
end
|
65
|
-
|
66
41
|
output_header "single"
|
67
42
|
|
68
|
-
|
69
|
-
if already_daemon
|
70
|
-
JRubyRestart.perm_daemonize
|
71
|
-
else
|
72
|
-
pid = nil
|
73
|
-
|
74
|
-
Signal.trap "SIGUSR2" do
|
75
|
-
log "* Started new process #{pid} as daemon..."
|
76
|
-
|
77
|
-
# Must use exit! so we don't unwind and run the ensures
|
78
|
-
# that will be run by the new child (such as deleting the
|
79
|
-
# pidfile)
|
80
|
-
exit!(true)
|
81
|
-
end
|
82
|
-
|
83
|
-
Signal.trap "SIGCHLD" do
|
84
|
-
log "! Error starting new process as daemon, exiting"
|
85
|
-
exit 1
|
86
|
-
end
|
87
|
-
|
88
|
-
jruby_daemon_start
|
89
|
-
sleep
|
90
|
-
end
|
91
|
-
else
|
92
|
-
if daemon?
|
93
|
-
log "* Daemonizing..."
|
94
|
-
Process.daemon(true)
|
95
|
-
redirect_io
|
96
|
-
end
|
97
|
-
|
98
|
-
load_and_bind
|
99
|
-
end
|
43
|
+
load_and_bind
|
100
44
|
|
101
45
|
Plugins.fire_background
|
102
46
|
|
@@ -106,10 +50,9 @@ module Puma
|
|
106
50
|
|
107
51
|
@server = server = start_server
|
108
52
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
end
|
53
|
+
|
54
|
+
log "Use Ctrl-C to stop"
|
55
|
+
redirect_io
|
113
56
|
|
114
57
|
@launcher.events.fire_on_booted!
|
115
58
|
|
data/lib/puma/state_file.rb
CHANGED
@@ -8,15 +8,18 @@ module Puma
|
|
8
8
|
@options = {}
|
9
9
|
end
|
10
10
|
|
11
|
-
def save(path)
|
12
|
-
File.
|
11
|
+
def save(path, permission = nil)
|
12
|
+
File.open(path, "w") do |file|
|
13
|
+
file.chmod(permission) if permission
|
14
|
+
file.write(YAML.dump(@options))
|
15
|
+
end
|
13
16
|
end
|
14
17
|
|
15
18
|
def load(path)
|
16
19
|
@options = YAML.load File.read(path)
|
17
20
|
end
|
18
21
|
|
19
|
-
FIELDS = %w!control_url control_auth_token pid!
|
22
|
+
FIELDS = %w!control_url control_auth_token pid running_from!
|
20
23
|
|
21
24
|
FIELDS.each do |f|
|
22
25
|
define_method f do
|
data/lib/puma/thread_pool.rb
CHANGED
@@ -47,6 +47,7 @@ module Puma
|
|
47
47
|
@shutdown = false
|
48
48
|
|
49
49
|
@trim_requested = 0
|
50
|
+
@out_of_band_pending = false
|
50
51
|
|
51
52
|
@workers = []
|
52
53
|
|
@@ -54,7 +55,10 @@ module Puma
|
|
54
55
|
@reaper = nil
|
55
56
|
|
56
57
|
@mutex.synchronize do
|
57
|
-
@min.times
|
58
|
+
@min.times do
|
59
|
+
spawn_thread
|
60
|
+
@not_full.wait(@mutex)
|
61
|
+
end
|
58
62
|
end
|
59
63
|
|
60
64
|
@clean_thread_locals = false
|
@@ -62,6 +66,7 @@ module Puma
|
|
62
66
|
|
63
67
|
attr_reader :spawned, :trim_requested, :waiting
|
64
68
|
attr_accessor :clean_thread_locals
|
69
|
+
attr_accessor :out_of_band_hook # @version 5.0.0
|
65
70
|
|
66
71
|
def self.clean_thread_locals
|
67
72
|
Thread.current.keys.each do |key| # rubocop: disable Performance/HashEachMethods
|
@@ -72,13 +77,18 @@ module Puma
|
|
72
77
|
# How many objects have yet to be processed by the pool?
|
73
78
|
#
|
74
79
|
def backlog
|
75
|
-
|
80
|
+
with_mutex { @todo.size }
|
76
81
|
end
|
77
82
|
|
78
83
|
def pool_capacity
|
79
84
|
waiting + (@max - spawned)
|
80
85
|
end
|
81
86
|
|
87
|
+
# @version 5.0.0
|
88
|
+
def busy_threads
|
89
|
+
with_mutex { @spawned - @waiting + @todo.size }
|
90
|
+
end
|
91
|
+
|
82
92
|
# :nodoc:
|
83
93
|
#
|
84
94
|
# Must be called with @mutex held!
|
@@ -99,48 +109,40 @@ module Puma
|
|
99
109
|
while true
|
100
110
|
work = nil
|
101
111
|
|
102
|
-
continue = true
|
103
|
-
|
104
112
|
mutex.synchronize do
|
105
113
|
while todo.empty?
|
106
114
|
if @trim_requested > 0
|
107
115
|
@trim_requested -= 1
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
end
|
112
|
-
|
113
|
-
if @shutdown
|
114
|
-
continue = false
|
115
|
-
break
|
116
|
+
@spawned -= 1
|
117
|
+
@workers.delete th
|
118
|
+
Thread.exit
|
116
119
|
end
|
117
120
|
|
118
121
|
@waiting += 1
|
122
|
+
if @out_of_band_pending && trigger_out_of_band_hook
|
123
|
+
@out_of_band_pending = false
|
124
|
+
end
|
119
125
|
not_full.signal
|
120
|
-
|
121
|
-
|
126
|
+
begin
|
127
|
+
not_empty.wait mutex
|
128
|
+
ensure
|
129
|
+
@waiting -= 1
|
130
|
+
end
|
122
131
|
end
|
123
132
|
|
124
|
-
work = todo.shift
|
133
|
+
work = todo.shift
|
125
134
|
end
|
126
135
|
|
127
|
-
break unless continue
|
128
|
-
|
129
136
|
if @clean_thread_locals
|
130
137
|
ThreadPool.clean_thread_locals
|
131
138
|
end
|
132
139
|
|
133
140
|
begin
|
134
|
-
block.call(work, *extra)
|
141
|
+
@out_of_band_pending = true if block.call(work, *extra)
|
135
142
|
rescue Exception => e
|
136
143
|
STDERR.puts "Error reached top of thread-pool: #{e.message} (#{e.class})"
|
137
144
|
end
|
138
145
|
end
|
139
|
-
|
140
|
-
mutex.synchronize do
|
141
|
-
@spawned -= 1
|
142
|
-
@workers.delete th
|
143
|
-
end
|
144
146
|
end
|
145
147
|
|
146
148
|
@workers << th
|
@@ -150,9 +152,32 @@ module Puma
|
|
150
152
|
|
151
153
|
private :spawn_thread
|
152
154
|
|
155
|
+
# @version 5.0.0
|
156
|
+
def trigger_out_of_band_hook
|
157
|
+
return false unless out_of_band_hook && out_of_band_hook.any?
|
158
|
+
|
159
|
+
# we execute on idle hook when all threads are free
|
160
|
+
return false unless @spawned == @waiting
|
161
|
+
|
162
|
+
out_of_band_hook.each(&:call)
|
163
|
+
true
|
164
|
+
rescue Exception => e
|
165
|
+
STDERR.puts "Exception calling out_of_band_hook: #{e.message} (#{e.class})"
|
166
|
+
true
|
167
|
+
end
|
168
|
+
|
169
|
+
private :trigger_out_of_band_hook
|
170
|
+
|
171
|
+
# @version 5.0.0
|
172
|
+
def with_mutex(&block)
|
173
|
+
@mutex.owned? ?
|
174
|
+
yield :
|
175
|
+
@mutex.synchronize(&block)
|
176
|
+
end
|
177
|
+
|
153
178
|
# Add +work+ to the todo list for a Thread to pickup and process.
|
154
179
|
def <<(work)
|
155
|
-
|
180
|
+
with_mutex do
|
156
181
|
if @shutdown
|
157
182
|
raise "Unable to add work while shutting down"
|
158
183
|
end
|
@@ -193,11 +218,8 @@ module Puma
|
|
193
218
|
# method would not block and another request would be added into the reactor
|
194
219
|
# by the server. This would continue until a fully bufferend request
|
195
220
|
# makes it through the reactor and can then be processed by the thread pool.
|
196
|
-
#
|
197
|
-
# Returns the current number of busy threads, or +nil+ if shutting down.
|
198
|
-
#
|
199
221
|
def wait_until_not_full
|
200
|
-
|
222
|
+
with_mutex do
|
201
223
|
while true
|
202
224
|
return if @shutdown
|
203
225
|
|
@@ -205,21 +227,41 @@ module Puma
|
|
205
227
|
# is work queued that cannot be handled by waiting
|
206
228
|
# threads, then accept more work until we would
|
207
229
|
# spin up the max number of threads.
|
208
|
-
|
209
|
-
return busy_threads if @max > busy_threads
|
230
|
+
return if busy_threads < @max
|
210
231
|
|
211
232
|
@not_full.wait @mutex
|
212
233
|
end
|
213
234
|
end
|
214
235
|
end
|
215
236
|
|
216
|
-
#
|
237
|
+
# @version 5.0.0
|
238
|
+
def wait_for_less_busy_worker(delay_s)
|
239
|
+
# Ruby MRI does GVL, this can result
|
240
|
+
# in processing contention when multiple threads
|
241
|
+
# (requests) are running concurrently
|
242
|
+
return unless Puma.mri?
|
243
|
+
return unless delay_s > 0
|
244
|
+
|
245
|
+
with_mutex do
|
246
|
+
return if @shutdown
|
247
|
+
|
248
|
+
# do not delay, if we are not busy
|
249
|
+
return unless busy_threads > 0
|
250
|
+
|
251
|
+
# this will be signaled once a request finishes,
|
252
|
+
# which can happen earlier than delay
|
253
|
+
@not_full.wait @mutex, delay_s
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
# If there are any free threads in the pool, tell one to go ahead
|
217
258
|
# and exit. If +force+ is true, then a trim request is requested
|
218
259
|
# even if all threads are being utilized.
|
219
260
|
#
|
220
261
|
def trim(force=false)
|
221
|
-
|
222
|
-
|
262
|
+
with_mutex do
|
263
|
+
free = @waiting - @todo.size
|
264
|
+
if (force or free > 0) and @spawned - @trim_requested > @min
|
223
265
|
@trim_requested += 1
|
224
266
|
@not_empty.signal
|
225
267
|
end
|
@@ -229,7 +271,7 @@ module Puma
|
|
229
271
|
# If there are dead threads in the pool make them go away while decreasing
|
230
272
|
# spawned counter so that new healthy threads could be created again.
|
231
273
|
def reap
|
232
|
-
|
274
|
+
with_mutex do
|
233
275
|
dead_workers = @workers.reject(&:alive?)
|
234
276
|
|
235
277
|
dead_workers.each do |worker|
|
@@ -281,10 +323,14 @@ module Puma
|
|
281
323
|
end
|
282
324
|
|
283
325
|
# Tell all threads in the pool to exit and wait for them to finish.
|
326
|
+
# Wait +timeout+ seconds then raise +ForceShutdown+ in remaining threads.
|
327
|
+
# Next, wait an extra +grace+ seconds then force-kill remaining threads.
|
328
|
+
# Finally, wait +kill_grace+ seconds for remaining threads to exit.
|
284
329
|
#
|
285
330
|
def shutdown(timeout=-1)
|
286
|
-
threads =
|
331
|
+
threads = with_mutex do
|
287
332
|
@shutdown = true
|
333
|
+
@trim_requested = @spawned
|
288
334
|
@not_empty.broadcast
|
289
335
|
@not_full.broadcast
|
290
336
|
|
@@ -298,27 +344,26 @@ module Puma
|
|
298
344
|
# Wait for threads to finish without force shutdown.
|
299
345
|
threads.each(&:join)
|
300
346
|
else
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
t.join
|
306
|
-
end
|
307
|
-
|
308
|
-
if threads.empty?
|
309
|
-
break
|
310
|
-
else
|
311
|
-
sleep 1
|
347
|
+
join = ->(inner_timeout) do
|
348
|
+
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
349
|
+
threads.reject! do |t|
|
350
|
+
elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
|
351
|
+
t.join inner_timeout - elapsed
|
312
352
|
end
|
313
353
|
end
|
314
354
|
|
355
|
+
# Wait +timeout+ seconds for threads to finish.
|
356
|
+
join.call(timeout)
|
357
|
+
|
358
|
+
# If threads are still running, raise ForceShutdown and wait to finish.
|
315
359
|
threads.each do |t|
|
316
360
|
t.raise ForceShutdown
|
317
361
|
end
|
362
|
+
join.call(SHUTDOWN_GRACE_TIME)
|
318
363
|
|
319
|
-
threads
|
320
|
-
|
321
|
-
|
364
|
+
# If threads are _still_ running, forcefully kill them and wait to finish.
|
365
|
+
threads.each(&:kill)
|
366
|
+
join.call(1)
|
322
367
|
end
|
323
368
|
|
324
369
|
@spawned = 0
|
data/lib/rack/handler/puma.rb
CHANGED
@@ -30,8 +30,6 @@ module Rack
|
|
30
30
|
end
|
31
31
|
|
32
32
|
conf = ::Puma::Configuration.new(options, default_options) do |user_config, file_config, default_config|
|
33
|
-
user_config.quiet
|
34
|
-
|
35
33
|
if options.delete(:Verbose)
|
36
34
|
app = Rack::CommonLogger.new(app, STDOUT)
|
37
35
|
end
|
@@ -61,7 +59,7 @@ module Rack
|
|
61
59
|
conf
|
62
60
|
end
|
63
61
|
|
64
|
-
def self.run(app, options
|
62
|
+
def self.run(app, **options)
|
65
63
|
conf = self.config(app, options)
|
66
64
|
|
67
65
|
events = options.delete(:Silent) ? ::Puma::Events.strings : ::Puma::Events.stdio
|
File without changes
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: puma
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 5.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Evan Phoenix
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-09-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nio4r
|
@@ -45,15 +45,22 @@ files:
|
|
45
45
|
- bin/pumactl
|
46
46
|
- docs/architecture.md
|
47
47
|
- docs/deployment.md
|
48
|
+
- docs/fork_worker.md
|
48
49
|
- docs/images/puma-connection-flow-no-reactor.png
|
49
50
|
- docs/images/puma-connection-flow.png
|
50
51
|
- docs/images/puma-general-arch.png
|
52
|
+
- docs/jungle/README.md
|
53
|
+
- docs/jungle/rc.d/README.md
|
54
|
+
- docs/jungle/rc.d/puma
|
55
|
+
- docs/jungle/rc.d/puma.conf
|
56
|
+
- docs/jungle/upstart/README.md
|
57
|
+
- docs/jungle/upstart/puma-manager.conf
|
58
|
+
- docs/jungle/upstart/puma.conf
|
51
59
|
- docs/nginx.md
|
52
60
|
- docs/plugins.md
|
53
61
|
- docs/restart.md
|
54
62
|
- docs/signals.md
|
55
63
|
- docs/systemd.md
|
56
|
-
- docs/tcp_mode.md
|
57
64
|
- ext/puma_http11/PumaHttp11Service.java
|
58
65
|
- ext/puma_http11/ext_help.h
|
59
66
|
- ext/puma_http11/extconf.rb
|
@@ -62,11 +69,10 @@ files:
|
|
62
69
|
- ext/puma_http11/http11_parser.java.rl
|
63
70
|
- ext/puma_http11/http11_parser.rl
|
64
71
|
- ext/puma_http11/http11_parser_common.rl
|
65
|
-
- ext/puma_http11/io_buffer.c
|
66
72
|
- ext/puma_http11/mini_ssl.c
|
73
|
+
- ext/puma_http11/no_ssl/PumaHttp11Service.java
|
67
74
|
- ext/puma_http11/org/jruby/puma/Http11.java
|
68
75
|
- ext/puma_http11/org/jruby/puma/Http11Parser.java
|
69
|
-
- ext/puma_http11/org/jruby/puma/IOBuffer.java
|
70
76
|
- ext/puma_http11/org/jruby/puma/MiniSSL.java
|
71
77
|
- ext/puma_http11/puma_http11.c
|
72
78
|
- lib/puma.rb
|
@@ -82,6 +88,7 @@ files:
|
|
82
88
|
- lib/puma/control_cli.rb
|
83
89
|
- lib/puma/detect.rb
|
84
90
|
- lib/puma/dsl.rb
|
91
|
+
- lib/puma/error_logger.rb
|
85
92
|
- lib/puma/events.rb
|
86
93
|
- lib/puma/io_buffer.rb
|
87
94
|
- lib/puma/jruby_restart.rb
|
@@ -99,29 +106,20 @@ files:
|
|
99
106
|
- lib/puma/server.rb
|
100
107
|
- lib/puma/single.rb
|
101
108
|
- lib/puma/state_file.rb
|
102
|
-
- lib/puma/tcp_logger.rb
|
103
109
|
- lib/puma/thread_pool.rb
|
104
110
|
- lib/puma/util.rb
|
105
111
|
- lib/rack/handler/puma.rb
|
106
|
-
- tools/
|
107
|
-
- tools/jungle/README.md
|
108
|
-
- tools/jungle/init.d/README.md
|
109
|
-
- tools/jungle/init.d/puma
|
110
|
-
- tools/jungle/init.d/run-puma
|
111
|
-
- tools/jungle/rc.d/README.md
|
112
|
-
- tools/jungle/rc.d/puma
|
113
|
-
- tools/jungle/rc.d/puma.conf
|
114
|
-
- tools/jungle/upstart/README.md
|
115
|
-
- tools/jungle/upstart/puma-manager.conf
|
116
|
-
- tools/jungle/upstart/puma.conf
|
112
|
+
- tools/Dockerfile
|
117
113
|
- tools/trickletest.rb
|
118
|
-
homepage:
|
114
|
+
homepage: https://puma.io
|
119
115
|
licenses:
|
120
116
|
- BSD-3-Clause
|
121
117
|
metadata:
|
122
|
-
|
118
|
+
bug_tracker_uri: https://github.com/puma/puma/issues
|
123
119
|
changelog_uri: https://github.com/puma/puma/blob/master/History.md
|
124
|
-
|
120
|
+
homepage_uri: https://puma.io
|
121
|
+
source_code_uri: https://github.com/puma/puma
|
122
|
+
post_install_message:
|
125
123
|
rdoc_options: []
|
126
124
|
require_paths:
|
127
125
|
- lib
|
@@ -136,8 +134,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
136
134
|
- !ruby/object:Gem::Version
|
137
135
|
version: '0'
|
138
136
|
requirements: []
|
139
|
-
rubygems_version: 3.
|
140
|
-
signing_key:
|
137
|
+
rubygems_version: 3.1.2
|
138
|
+
signing_key:
|
141
139
|
specification_version: 4
|
142
140
|
summary: Puma is a simple, fast, threaded, and highly concurrent HTTP 1.1 server for
|
143
141
|
Ruby/Rack applications
|