puma 3.12.1 → 4.1.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 +75 -5
- data/README.md +90 -33
- data/docs/architecture.md +1 -0
- data/docs/deployment.md +24 -4
- data/docs/restart.md +4 -2
- data/docs/systemd.md +27 -9
- data/ext/puma_http11/PumaHttp11Service.java +2 -0
- data/ext/puma_http11/extconf.rb +8 -0
- data/ext/puma_http11/mini_ssl.c +78 -8
- data/ext/puma_http11/org/jruby/puma/IOBuffer.java +72 -0
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +15 -4
- data/lib/puma.rb +2 -0
- data/lib/puma/accept_nonblock.rb +2 -0
- data/lib/puma/app/status.rb +7 -2
- data/lib/puma/binder.rb +11 -1
- data/lib/puma/client.rb +64 -30
- data/lib/puma/cluster.rb +44 -17
- data/lib/puma/configuration.rb +4 -3
- data/lib/puma/const.rb +9 -2
- data/lib/puma/control_cli.rb +10 -2
- data/lib/puma/dsl.rb +280 -74
- data/lib/puma/events.rb +6 -3
- data/lib/puma/io_buffer.rb +1 -6
- data/lib/puma/launcher.rb +15 -14
- data/lib/puma/minissl.rb +35 -17
- data/lib/puma/plugin/tmp_restart.rb +2 -0
- data/lib/puma/rack/builder.rb +2 -0
- data/lib/puma/rack/urlmap.rb +2 -0
- data/lib/puma/rack_default.rb +2 -0
- data/lib/puma/reactor.rb +104 -53
- data/lib/puma/runner.rb +2 -1
- data/lib/puma/server.rb +44 -36
- data/lib/puma/single.rb +3 -3
- data/lib/puma/thread_pool.rb +5 -1
- data/lib/puma/util.rb +1 -6
- data/lib/rack/handler/puma.rb +3 -1
- data/tools/jungle/init.d/puma +6 -6
- metadata +22 -11
- data/lib/puma/compat.rb +0 -14
- data/lib/puma/java_io_buffer.rb +0 -47
- data/lib/puma/rack/backports/uri/common_193.rb +0 -33
data/lib/puma/events.rb
CHANGED
@@ -29,8 +29,8 @@ module Puma
|
|
29
29
|
#
|
30
30
|
def initialize(stdout, stderr)
|
31
31
|
@formatter = DefaultFormatter.new
|
32
|
-
@stdout = stdout
|
33
|
-
@stderr = stderr
|
32
|
+
@stdout = stdout.dup
|
33
|
+
@stderr = stderr.dup
|
34
34
|
|
35
35
|
@stdout.sync = true
|
36
36
|
@stderr.sync = true
|
@@ -93,7 +93,10 @@ module Puma
|
|
93
93
|
# parsing exception.
|
94
94
|
#
|
95
95
|
def parse_error(server, env, error)
|
96
|
-
@stderr.puts "#{Time.now}: HTTP parse error, malformed request
|
96
|
+
@stderr.puts "#{Time.now}: HTTP parse error, malformed request " \
|
97
|
+
"(#{env[HTTP_X_FORWARDED_FOR] || env[REMOTE_ADDR]}#{env[REQUEST_PATH]}): " \
|
98
|
+
"#{error.inspect}" \
|
99
|
+
"\n---\n"
|
97
100
|
end
|
98
101
|
|
99
102
|
# An SSL error has occurred.
|
data/lib/puma/io_buffer.rb
CHANGED
data/lib/puma/launcher.rb
CHANGED
@@ -63,6 +63,9 @@ module Puma
|
|
63
63
|
@options = @config.options
|
64
64
|
@config.clamp
|
65
65
|
|
66
|
+
@events.formatter = Events::PidFormatter.new if clustered?
|
67
|
+
@events.formatter = options[:log_formatter] if @options[:log_formatter]
|
68
|
+
|
66
69
|
generate_restart_data
|
67
70
|
|
68
71
|
if clustered? && !Process.respond_to?(:fork)
|
@@ -81,7 +84,6 @@ module Puma
|
|
81
84
|
set_rack_environment
|
82
85
|
|
83
86
|
if clustered?
|
84
|
-
@events.formatter = Events::PidFormatter.new
|
85
87
|
@options[:logger] = @events
|
86
88
|
|
87
89
|
@runner = Cluster.new(self, @events)
|
@@ -214,6 +216,15 @@ module Puma
|
|
214
216
|
end
|
215
217
|
end
|
216
218
|
|
219
|
+
def close_binder_listeners
|
220
|
+
@binder.listeners.each do |l, io|
|
221
|
+
io.close
|
222
|
+
uri = URI.parse(l)
|
223
|
+
next unless uri.scheme == 'unix'
|
224
|
+
File.unlink("#{uri.host}#{uri.path}")
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
217
228
|
private
|
218
229
|
|
219
230
|
def reload_worker_directory
|
@@ -243,7 +254,7 @@ module Puma
|
|
243
254
|
|
244
255
|
argv = restart_args
|
245
256
|
Dir.chdir(@restart_dir)
|
246
|
-
argv += [redirects]
|
257
|
+
argv += [redirects]
|
247
258
|
Kernel.exec(*argv)
|
248
259
|
end
|
249
260
|
end
|
@@ -272,7 +283,7 @@ module Puma
|
|
272
283
|
wild = File.expand_path(File.join(puma_lib_dir, "../bin/puma-wild"))
|
273
284
|
args = [Gem.ruby, wild, '-I', dirs.join(':'), deps.join(',')] + @original_argv
|
274
285
|
# Ruby 2.0+ defaults to true which breaks socket activation
|
275
|
-
args += [{:close_others => false}]
|
286
|
+
args += [{:close_others => false}]
|
276
287
|
Kernel.exec(*args)
|
277
288
|
end
|
278
289
|
end
|
@@ -319,16 +330,6 @@ module Puma
|
|
319
330
|
@options[:prune_bundler] && clustered? && !@options[:preload_app]
|
320
331
|
end
|
321
332
|
|
322
|
-
def close_binder_listeners
|
323
|
-
@binder.listeners.each do |l, io|
|
324
|
-
io.close
|
325
|
-
uri = URI.parse(l)
|
326
|
-
next unless uri.scheme == 'unix'
|
327
|
-
File.unlink("#{uri.host}#{uri.path}")
|
328
|
-
end
|
329
|
-
end
|
330
|
-
|
331
|
-
|
332
333
|
def generate_restart_data
|
333
334
|
if dir = @options[:directory]
|
334
335
|
@restart_dir = dir
|
@@ -397,7 +398,7 @@ module Puma
|
|
397
398
|
Signal.trap "SIGTERM" do
|
398
399
|
graceful_stop
|
399
400
|
|
400
|
-
raise
|
401
|
+
raise(SignalException, "SIGTERM") if @options[:raise_exception_on_sigterm]
|
401
402
|
end
|
402
403
|
rescue Exception
|
403
404
|
log "*** SIGTERM not implemented, signal based gracefully stopping unavailable!"
|
data/lib/puma/minissl.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
begin
|
4
4
|
require 'io/wait'
|
5
|
-
|
5
|
+
rescue LoadError
|
6
6
|
end
|
7
7
|
|
8
8
|
module Puma
|
@@ -54,22 +54,21 @@ module Puma
|
|
54
54
|
output = engine_read_all
|
55
55
|
return output if output
|
56
56
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
end while true
|
57
|
+
data = @socket.read_nonblock(size, exception: false)
|
58
|
+
if data == :wait_readable || data == :wait_writable
|
59
|
+
# It would make more sense to let @socket.read_nonblock raise
|
60
|
+
# EAGAIN if necessary but it seems like it'll misbehave on Windows.
|
61
|
+
# I don't have a Windows machine to debug this so I can't explain
|
62
|
+
# exactly whats happening in that OS. Please let me know if you
|
63
|
+
# find out!
|
64
|
+
#
|
65
|
+
# In the meantime, we can emulate the correct behavior by
|
66
|
+
# capturing :wait_readable & :wait_writable and raising EAGAIN
|
67
|
+
# ourselves.
|
68
|
+
raise IO::EAGAINWaitReadable
|
69
|
+
elsif data.nil?
|
70
|
+
return nil
|
71
|
+
end
|
73
72
|
|
74
73
|
@engine.inject(data)
|
75
74
|
output = engine_read_all
|
@@ -177,6 +176,12 @@ module Puma
|
|
177
176
|
|
178
177
|
class Context
|
179
178
|
attr_accessor :verify_mode
|
179
|
+
attr_reader :no_tlsv1, :no_tlsv1_1
|
180
|
+
|
181
|
+
def initialize
|
182
|
+
@no_tlsv1 = false
|
183
|
+
@no_tlsv1_1 = false
|
184
|
+
end
|
180
185
|
|
181
186
|
if defined?(JRUBY_VERSION)
|
182
187
|
# jruby-specific Context properties: java uses a keystore and password pair rather than a cert/key pair
|
@@ -220,6 +225,19 @@ module Puma
|
|
220
225
|
raise "Cert not configured" unless @cert
|
221
226
|
end
|
222
227
|
end
|
228
|
+
|
229
|
+
# disables TLSv1
|
230
|
+
def no_tlsv1=(tlsv1)
|
231
|
+
raise ArgumentError, "Invalid value of no_tlsv1" unless ['true', 'false', true, false].include?(tlsv1)
|
232
|
+
@no_tlsv1 = tlsv1
|
233
|
+
end
|
234
|
+
|
235
|
+
# disables TLSv1 and TLSv1.1. Overrides `#no_tlsv1=`
|
236
|
+
def no_tlsv1_1=(tlsv1_1)
|
237
|
+
raise ArgumentError, "Invalid value of no_tlsv1" unless ['true', 'false', true, false].include?(tlsv1_1)
|
238
|
+
@no_tlsv1_1 = tlsv1_1
|
239
|
+
end
|
240
|
+
|
223
241
|
end
|
224
242
|
|
225
243
|
VERIFY_NONE = 0
|
data/lib/puma/rack/builder.rb
CHANGED
data/lib/puma/rack/urlmap.rb
CHANGED
data/lib/puma/rack_default.rb
CHANGED
data/lib/puma/reactor.rb
CHANGED
@@ -3,6 +3,8 @@
|
|
3
3
|
require 'puma/util'
|
4
4
|
require 'puma/minissl'
|
5
5
|
|
6
|
+
require 'nio'
|
7
|
+
|
6
8
|
module Puma
|
7
9
|
# Internal Docs, Not a public interface.
|
8
10
|
#
|
@@ -18,12 +20,13 @@ module Puma
|
|
18
20
|
#
|
19
21
|
# ## Reactor Flow
|
20
22
|
#
|
21
|
-
# A
|
22
|
-
#
|
23
|
+
# A connection comes into a `Puma::Server` instance, it is then passed to a `Puma::Reactor` instance,
|
24
|
+
# which stores it in an array and waits for any of the connections to be ready for reading.
|
23
25
|
#
|
24
|
-
#
|
26
|
+
# The waiting/wake up is performed with nio4r, which will use the appropriate backend (libev, Java NIO or
|
27
|
+
# just plain IO#select). The call to `NIO::Selector#select` will "wake up" and
|
25
28
|
# return the references to any objects that caused it to "wake". The reactor
|
26
|
-
# then loops through each of these request objects, and sees if they're
|
29
|
+
# then loops through each of these request objects, and sees if they're complete. If they
|
27
30
|
# have a full header and body then the reactor passes the request to a thread pool.
|
28
31
|
# Once in a thread pool, a "worker thread" can run the the application's Ruby code against the request.
|
29
32
|
#
|
@@ -38,7 +41,7 @@ module Puma
|
|
38
41
|
# Creates an instance of Puma::Reactor
|
39
42
|
#
|
40
43
|
# The `server` argument is an instance of `Puma::Server`
|
41
|
-
#
|
44
|
+
# that is used to write a response for "low level errors"
|
42
45
|
# when there is an exception inside of the reactor.
|
43
46
|
#
|
44
47
|
# The `app_pool` is an instance of `Puma::ThreadPool`.
|
@@ -49,6 +52,8 @@ module Puma
|
|
49
52
|
@events = server.events
|
50
53
|
@app_pool = app_pool
|
51
54
|
|
55
|
+
@selector = NIO::Selector.new
|
56
|
+
|
52
57
|
@mutex = Mutex.new
|
53
58
|
|
54
59
|
# Read / Write pipes to wake up internal while loop
|
@@ -57,24 +62,26 @@ module Puma
|
|
57
62
|
@sleep_for = DefaultSleepFor
|
58
63
|
@timeouts = []
|
59
64
|
|
60
|
-
|
65
|
+
mon = @selector.register(@ready, :r)
|
66
|
+
mon.value = @ready
|
67
|
+
|
68
|
+
@monitors = [mon]
|
61
69
|
end
|
62
70
|
|
63
71
|
private
|
64
72
|
|
65
|
-
|
66
73
|
# Until a request is added via the `add` method this method will internally
|
67
74
|
# loop, waiting on the `sockets` array objects. The only object in this
|
68
75
|
# array at first is the `@ready` IO object, which is the read end of a pipe
|
69
76
|
# connected to `@trigger` object. When `@trigger` is written to, then the loop
|
70
|
-
# will break on `
|
77
|
+
# will break on `NIO::Selector#select` and return an array.
|
71
78
|
#
|
72
79
|
# ## When a request is added:
|
73
80
|
#
|
74
81
|
# When the `add` method is called, an instance of `Puma::Client` is added to the `@input` array.
|
75
82
|
# Next the `@ready` pipe is "woken" by writing a string of `"*"` to `@trigger`.
|
76
83
|
#
|
77
|
-
# When that happens, the internal loop stops blocking at `
|
84
|
+
# When that happens, the internal loop stops blocking at `NIO::Selector#select` and returns a reference
|
78
85
|
# to whatever "woke" it up. On the very first loop, the only thing in `sockets` is `@ready`.
|
79
86
|
# When `@trigger` is written-to, the loop "wakes" and the `ready`
|
80
87
|
# variable returns an array of arrays that looks like `[[#<IO:fd 10>], [], []]` where the
|
@@ -90,11 +97,11 @@ module Puma
|
|
90
97
|
# to the `@ready` IO object. For example: `[#<IO:fd 10>, #<Puma::Client:0x3fdc1103bee8 @ready=false>]`.
|
91
98
|
#
|
92
99
|
# Since the `Puma::Client` in this example has data that has not been read yet,
|
93
|
-
# the `
|
100
|
+
# the `NIO::Selector#select` is immediately able to "wake" and read from the `Puma::Client`. At this point the
|
94
101
|
# `ready` output looks like this: `[[#<Puma::Client:0x3fdc1103bee8 @ready=false>], [], []]`.
|
95
102
|
#
|
96
103
|
# Each element in the first entry is iterated over. The `Puma::Client` object is not
|
97
|
-
# the `@ready` pipe, so the reactor checks to see if it has the
|
104
|
+
# the `@ready` pipe, so the reactor checks to see if it has the full header and body with
|
98
105
|
# the `Puma::Client#try_to_finish` method. If the full request has been sent,
|
99
106
|
# then the request is passed off to the `@app_pool` thread pool so that a "worker thread"
|
100
107
|
# can pick up the request and begin to execute application logic. This is done
|
@@ -102,56 +109,93 @@ module Puma
|
|
102
109
|
#
|
103
110
|
# If the request body is not present then nothing will happen, and the loop will iterate
|
104
111
|
# again. When the client sends more data to the socket the `Puma::Client` object will
|
105
|
-
# wake up the `
|
112
|
+
# wake up the `NIO::Selector#select` and it can again be checked to see if it's ready to be
|
106
113
|
# passed to the thread pool.
|
107
114
|
#
|
108
115
|
# ## Time Out Case
|
109
116
|
#
|
110
|
-
# In addition to being woken via a write to one of the sockets the `
|
117
|
+
# In addition to being woken via a write to one of the sockets the `NIO::Selector#select` will
|
111
118
|
# periodically "time out" of the sleep. One of the functions of this is to check for
|
112
119
|
# any requests that have "timed out". At the end of the loop it's checked to see if
|
113
|
-
# the first element in the `@timeout` array has exceed
|
114
|
-
# the client object is removed from the timeout
|
115
|
-
# Then
|
120
|
+
# the first element in the `@timeout` array has exceed its allowed time. If so,
|
121
|
+
# the client object is removed from the timeout array, a 408 response is written.
|
122
|
+
# Then its connection is closed, and the object is removed from the `sockets` array
|
116
123
|
# that watches for new data.
|
117
124
|
#
|
118
125
|
# This behavior loops until all the objects that have timed out have been removed.
|
119
126
|
#
|
120
|
-
# Once all the timeouts have been processed, the next duration of the `
|
127
|
+
# Once all the timeouts have been processed, the next duration of the `NIO::Selector#select` sleep
|
121
128
|
# will be set to be equal to the amount of time it will take for the next timeout to occur.
|
122
129
|
# This calculation happens in `calculate_sleep`.
|
123
130
|
def run_internal
|
124
|
-
|
131
|
+
monitors = @monitors
|
132
|
+
selector = @selector
|
125
133
|
|
126
134
|
while true
|
127
135
|
begin
|
128
|
-
ready =
|
136
|
+
ready = selector.select @sleep_for
|
129
137
|
rescue IOError => e
|
130
138
|
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
|
131
|
-
if
|
139
|
+
if monitors.any? { |mon| mon.value.closed? }
|
132
140
|
STDERR.puts "Error in select: #{e.message} (#{e.class})"
|
133
141
|
STDERR.puts e.backtrace
|
134
|
-
|
142
|
+
|
143
|
+
monitors.reject! do |mon|
|
144
|
+
if mon.value.closed?
|
145
|
+
selector.deregister mon.value
|
146
|
+
true
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
135
150
|
retry
|
136
151
|
else
|
137
152
|
raise
|
138
153
|
end
|
139
154
|
end
|
140
155
|
|
141
|
-
if ready
|
142
|
-
|
143
|
-
if
|
156
|
+
if ready
|
157
|
+
ready.each do |mon|
|
158
|
+
if mon.value == @ready
|
144
159
|
@mutex.synchronize do
|
145
160
|
case @ready.read(1)
|
146
161
|
when "*"
|
147
|
-
|
162
|
+
@input.each do |c|
|
163
|
+
mon = nil
|
164
|
+
begin
|
165
|
+
begin
|
166
|
+
mon = selector.register(c, :r)
|
167
|
+
rescue ArgumentError
|
168
|
+
# There is a bug where we seem to be registering an already registered
|
169
|
+
# client. This code deals with this situation but I wish we didn't have to.
|
170
|
+
monitors.delete_if { |submon| submon.value.to_io == c.to_io }
|
171
|
+
selector.deregister(c)
|
172
|
+
mon = selector.register(c, :r)
|
173
|
+
end
|
174
|
+
rescue IOError
|
175
|
+
# Means that the io is closed, so we should ignore this request
|
176
|
+
# entirely
|
177
|
+
else
|
178
|
+
mon.value = c
|
179
|
+
@timeouts << mon if c.timeout_at
|
180
|
+
monitors << mon
|
181
|
+
end
|
182
|
+
end
|
148
183
|
@input.clear
|
184
|
+
|
185
|
+
@timeouts.sort! { |a,b| a.value.timeout_at <=> b.value.timeout_at }
|
186
|
+
calculate_sleep
|
149
187
|
when "c"
|
150
|
-
|
151
|
-
if
|
188
|
+
monitors.reject! do |submon|
|
189
|
+
if submon.value == @ready
|
152
190
|
false
|
153
191
|
else
|
154
|
-
|
192
|
+
submon.value.close
|
193
|
+
begin
|
194
|
+
selector.deregister submon.value
|
195
|
+
rescue IOError
|
196
|
+
# nio4r on jruby seems to throw an IOError here if the IO is closed, so
|
197
|
+
# we need to swallow it.
|
198
|
+
end
|
155
199
|
true
|
156
200
|
end
|
157
201
|
end
|
@@ -160,19 +204,21 @@ module Puma
|
|
160
204
|
end
|
161
205
|
end
|
162
206
|
else
|
207
|
+
c = mon.value
|
208
|
+
|
163
209
|
# We have to be sure to remove it from the timeout
|
164
210
|
# list or we'll accidentally close the socket when
|
165
211
|
# it's in use!
|
166
212
|
if c.timeout_at
|
167
213
|
@mutex.synchronize do
|
168
|
-
@timeouts.delete
|
214
|
+
@timeouts.delete mon
|
169
215
|
end
|
170
216
|
end
|
171
217
|
|
172
218
|
begin
|
173
219
|
if c.try_to_finish
|
174
220
|
@app_pool << c
|
175
|
-
|
221
|
+
clear_monitor mon
|
176
222
|
end
|
177
223
|
|
178
224
|
# Don't report these to the lowlevel_error handler, otherwise
|
@@ -182,18 +228,23 @@ module Puma
|
|
182
228
|
c.write_500
|
183
229
|
c.close
|
184
230
|
|
185
|
-
|
231
|
+
clear_monitor mon
|
186
232
|
|
187
233
|
# SSL handshake failure
|
188
234
|
rescue MiniSSL::SSLError => e
|
189
235
|
@server.lowlevel_error(e, c.env)
|
190
236
|
|
191
237
|
ssl_socket = c.io
|
192
|
-
|
238
|
+
begin
|
239
|
+
addr = ssl_socket.peeraddr.last
|
240
|
+
rescue IOError
|
241
|
+
addr = "<unknown>"
|
242
|
+
end
|
243
|
+
|
193
244
|
cert = ssl_socket.peercert
|
194
245
|
|
195
246
|
c.close
|
196
|
-
|
247
|
+
clear_monitor mon
|
197
248
|
|
198
249
|
@events.ssl_error @server, addr, cert, e
|
199
250
|
|
@@ -204,7 +255,7 @@ module Puma
|
|
204
255
|
c.write_400
|
205
256
|
c.close
|
206
257
|
|
207
|
-
|
258
|
+
clear_monitor mon
|
208
259
|
|
209
260
|
@events.parse_error @server, c.env, e
|
210
261
|
rescue StandardError => e
|
@@ -213,7 +264,7 @@ module Puma
|
|
213
264
|
c.write_500
|
214
265
|
c.close
|
215
266
|
|
216
|
-
|
267
|
+
clear_monitor mon
|
217
268
|
end
|
218
269
|
end
|
219
270
|
end
|
@@ -223,11 +274,13 @@ module Puma
|
|
223
274
|
@mutex.synchronize do
|
224
275
|
now = Time.now
|
225
276
|
|
226
|
-
while @timeouts.first.timeout_at < now
|
227
|
-
|
277
|
+
while @timeouts.first.value.timeout_at < now
|
278
|
+
mon = @timeouts.shift
|
279
|
+
c = mon.value
|
228
280
|
c.write_408 if c.in_data_phase
|
229
281
|
c.close
|
230
|
-
|
282
|
+
|
283
|
+
clear_monitor mon
|
231
284
|
|
232
285
|
break if @timeouts.empty?
|
233
286
|
end
|
@@ -238,6 +291,11 @@ module Puma
|
|
238
291
|
end
|
239
292
|
end
|
240
293
|
|
294
|
+
def clear_monitor(mon)
|
295
|
+
@selector.deregister mon.value
|
296
|
+
@monitors.delete mon
|
297
|
+
end
|
298
|
+
|
241
299
|
public
|
242
300
|
|
243
301
|
def run
|
@@ -262,7 +320,7 @@ module Puma
|
|
262
320
|
end
|
263
321
|
end
|
264
322
|
|
265
|
-
# The `calculate_sleep` sets the value that the `
|
323
|
+
# The `calculate_sleep` sets the value that the `NIO::Selector#select` will
|
266
324
|
# sleep for in the main reactor loop when no sockets are being written to.
|
267
325
|
#
|
268
326
|
# The values kept in `@timeouts` are sorted so that the first timeout
|
@@ -276,7 +334,7 @@ module Puma
|
|
276
334
|
if @timeouts.empty?
|
277
335
|
@sleep_for = DefaultSleepFor
|
278
336
|
else
|
279
|
-
diff = @timeouts.first.timeout_at.to_f - Time.now.to_f
|
337
|
+
diff = @timeouts.first.value.timeout_at.to_f - Time.now.to_f
|
280
338
|
|
281
339
|
if diff < 0.0
|
282
340
|
@sleep_for = 0
|
@@ -293,18 +351,18 @@ module Puma
|
|
293
351
|
# object.
|
294
352
|
#
|
295
353
|
# The main body of the reactor loop is in `run_internal` and it
|
296
|
-
# will sleep on `
|
297
|
-
# reactor it cannot be added directly to the `sockets`
|
298
|
-
# the `
|
354
|
+
# will sleep on `NIO::Selector#select`. When a new connection is added to the
|
355
|
+
# reactor it cannot be added directly to the `sockets` array, because
|
356
|
+
# the `NIO::Selector#select` will not be watching for it yet.
|
299
357
|
#
|
300
|
-
# Instead what needs to happen is that `
|
358
|
+
# Instead what needs to happen is that `NIO::Selector#select` needs to be woken up,
|
301
359
|
# the contents of `@input` added to the `sockets` array, and then
|
302
|
-
# another call to `
|
360
|
+
# another call to `NIO::Selector#select` needs to happen. Since the `Puma::Client`
|
303
361
|
# object can be read immediately, it does not block, but instead returns
|
304
362
|
# right away.
|
305
363
|
#
|
306
364
|
# This behavior is accomplished by writing to `@trigger` which wakes up
|
307
|
-
# the `
|
365
|
+
# the `NIO::Selector#select` and then there is logic to detect the value of `*`,
|
308
366
|
# pull the contents from `@input` and add them to the sockets array.
|
309
367
|
#
|
310
368
|
# If the object passed in has a timeout value in `timeout_at` then
|
@@ -315,13 +373,6 @@ module Puma
|
|
315
373
|
@mutex.synchronize do
|
316
374
|
@input << c
|
317
375
|
@trigger << "*"
|
318
|
-
|
319
|
-
if c.timeout_at
|
320
|
-
@timeouts << c
|
321
|
-
@timeouts.sort! { |a,b| a.timeout_at <=> b.timeout_at }
|
322
|
-
|
323
|
-
calculate_sleep
|
324
|
-
end
|
325
376
|
end
|
326
377
|
end
|
327
378
|
|