puma-simon 3.7.1

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.
Files changed (157) hide show
  1. checksums.yaml +7 -0
  2. data/.github/issue_template.md +20 -0
  3. data/.gitignore +18 -0
  4. data/.hoeignore +12 -0
  5. data/.travis.yml +29 -0
  6. data/DEPLOYMENT.md +91 -0
  7. data/Gemfile +12 -0
  8. data/History.md +1254 -0
  9. data/LICENSE +26 -0
  10. data/Manifest.txt +78 -0
  11. data/README.md +353 -0
  12. data/Rakefile +158 -0
  13. data/Release.md +9 -0
  14. data/bin/puma +10 -0
  15. data/bin/puma-wild +31 -0
  16. data/bin/pumactl +12 -0
  17. data/docs/nginx.md +80 -0
  18. data/docs/signals.md +43 -0
  19. data/docs/systemd.md +197 -0
  20. data/examples/CA/cacert.pem +23 -0
  21. data/examples/CA/newcerts/cert_1.pem +19 -0
  22. data/examples/CA/newcerts/cert_2.pem +19 -0
  23. data/examples/CA/private/cakeypair.pem +30 -0
  24. data/examples/CA/serial +1 -0
  25. data/examples/config.rb +200 -0
  26. data/examples/plugins/redis_stop_puma.rb +46 -0
  27. data/examples/puma/cert_puma.pem +19 -0
  28. data/examples/puma/client-certs/ca.crt +19 -0
  29. data/examples/puma/client-certs/ca.key +27 -0
  30. data/examples/puma/client-certs/client.crt +19 -0
  31. data/examples/puma/client-certs/client.key +27 -0
  32. data/examples/puma/client-certs/client_expired.crt +19 -0
  33. data/examples/puma/client-certs/client_expired.key +27 -0
  34. data/examples/puma/client-certs/client_unknown.crt +19 -0
  35. data/examples/puma/client-certs/client_unknown.key +27 -0
  36. data/examples/puma/client-certs/generate.rb +78 -0
  37. data/examples/puma/client-certs/keystore.jks +0 -0
  38. data/examples/puma/client-certs/server.crt +19 -0
  39. data/examples/puma/client-certs/server.key +27 -0
  40. data/examples/puma/client-certs/server.p12 +0 -0
  41. data/examples/puma/client-certs/unknown_ca.crt +19 -0
  42. data/examples/puma/client-certs/unknown_ca.key +27 -0
  43. data/examples/puma/csr_puma.pem +11 -0
  44. data/examples/puma/keystore.jks +0 -0
  45. data/examples/puma/puma_keypair.pem +15 -0
  46. data/examples/qc_config.rb +13 -0
  47. data/ext/puma_http11/PumaHttp11Service.java +17 -0
  48. data/ext/puma_http11/ext_help.h +15 -0
  49. data/ext/puma_http11/extconf.rb +15 -0
  50. data/ext/puma_http11/http11_parser.c +1069 -0
  51. data/ext/puma_http11/http11_parser.h +65 -0
  52. data/ext/puma_http11/http11_parser.java.rl +161 -0
  53. data/ext/puma_http11/http11_parser.rl +147 -0
  54. data/ext/puma_http11/http11_parser_common.rl +54 -0
  55. data/ext/puma_http11/io_buffer.c +155 -0
  56. data/ext/puma_http11/mini_ssl.c +457 -0
  57. data/ext/puma_http11/org/jruby/puma/Http11.java +234 -0
  58. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +473 -0
  59. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +339 -0
  60. data/ext/puma_http11/puma_http11.c +500 -0
  61. data/gemfiles/2.1-Gemfile +12 -0
  62. data/lib/puma.rb +15 -0
  63. data/lib/puma/accept_nonblock.rb +23 -0
  64. data/lib/puma/app/status.rb +66 -0
  65. data/lib/puma/binder.rb +402 -0
  66. data/lib/puma/cli.rb +220 -0
  67. data/lib/puma/client.rb +434 -0
  68. data/lib/puma/cluster.rb +510 -0
  69. data/lib/puma/commonlogger.rb +106 -0
  70. data/lib/puma/compat.rb +14 -0
  71. data/lib/puma/configuration.rb +364 -0
  72. data/lib/puma/const.rb +224 -0
  73. data/lib/puma/control_cli.rb +259 -0
  74. data/lib/puma/convenient.rb +23 -0
  75. data/lib/puma/daemon_ext.rb +31 -0
  76. data/lib/puma/delegation.rb +11 -0
  77. data/lib/puma/detect.rb +13 -0
  78. data/lib/puma/dsl.rb +486 -0
  79. data/lib/puma/events.rb +152 -0
  80. data/lib/puma/io_buffer.rb +7 -0
  81. data/lib/puma/java_io_buffer.rb +45 -0
  82. data/lib/puma/jruby_restart.rb +83 -0
  83. data/lib/puma/launcher.rb +410 -0
  84. data/lib/puma/minissl.rb +221 -0
  85. data/lib/puma/null_io.rb +42 -0
  86. data/lib/puma/plugin.rb +115 -0
  87. data/lib/puma/plugin/tmp_restart.rb +35 -0
  88. data/lib/puma/rack/backports/uri/common_193.rb +33 -0
  89. data/lib/puma/rack/builder.rb +298 -0
  90. data/lib/puma/rack/urlmap.rb +91 -0
  91. data/lib/puma/rack_default.rb +7 -0
  92. data/lib/puma/reactor.rb +210 -0
  93. data/lib/puma/runner.rb +171 -0
  94. data/lib/puma/server.rb +949 -0
  95. data/lib/puma/single.rb +112 -0
  96. data/lib/puma/state_file.rb +29 -0
  97. data/lib/puma/tcp_logger.rb +39 -0
  98. data/lib/puma/thread_pool.rb +297 -0
  99. data/lib/puma/util.rb +128 -0
  100. data/lib/rack/handler/puma.rb +78 -0
  101. data/puma.gemspec +52 -0
  102. data/test/ab_rs.rb +22 -0
  103. data/test/config.rb +2 -0
  104. data/test/config/app.rb +9 -0
  105. data/test/config/plugin.rb +1 -0
  106. data/test/config/settings.rb +2 -0
  107. data/test/config/state_file_testing_config.rb +14 -0
  108. data/test/hello-bind.ru +2 -0
  109. data/test/hello-delay.ru +3 -0
  110. data/test/hello-map.ru +3 -0
  111. data/test/hello-post.ru +4 -0
  112. data/test/hello-stuck.ru +1 -0
  113. data/test/hello-tcp.ru +5 -0
  114. data/test/hello.ru +1 -0
  115. data/test/hijack.ru +6 -0
  116. data/test/hijack2.ru +5 -0
  117. data/test/lobster.ru +4 -0
  118. data/test/shell/run.sh +24 -0
  119. data/test/shell/t1.rb +19 -0
  120. data/test/shell/t1_conf.rb +3 -0
  121. data/test/shell/t2.rb +17 -0
  122. data/test/shell/t2_conf.rb +6 -0
  123. data/test/shell/t3.rb +25 -0
  124. data/test/shell/t3_conf.rb +5 -0
  125. data/test/slow.ru +4 -0
  126. data/test/ssl_config.rb +4 -0
  127. data/test/test_app_status.rb +93 -0
  128. data/test/test_binder.rb +31 -0
  129. data/test/test_cli.rb +209 -0
  130. data/test/test_config.rb +95 -0
  131. data/test/test_events.rb +161 -0
  132. data/test/test_helper.rb +50 -0
  133. data/test/test_http10.rb +27 -0
  134. data/test/test_http11.rb +186 -0
  135. data/test/test_integration.rb +247 -0
  136. data/test/test_iobuffer.rb +39 -0
  137. data/test/test_minissl.rb +29 -0
  138. data/test/test_null_io.rb +49 -0
  139. data/test/test_persistent.rb +245 -0
  140. data/test/test_puma_server.rb +626 -0
  141. data/test/test_puma_server_ssl.rb +222 -0
  142. data/test/test_rack_handler.rb +57 -0
  143. data/test/test_rack_server.rb +138 -0
  144. data/test/test_tcp_logger.rb +39 -0
  145. data/test/test_tcp_rack.rb +36 -0
  146. data/test/test_thread_pool.rb +250 -0
  147. data/test/test_unix_socket.rb +35 -0
  148. data/test/test_web_server.rb +88 -0
  149. data/tools/jungle/README.md +9 -0
  150. data/tools/jungle/init.d/README.md +59 -0
  151. data/tools/jungle/init.d/puma +421 -0
  152. data/tools/jungle/init.d/run-puma +18 -0
  153. data/tools/jungle/upstart/README.md +61 -0
  154. data/tools/jungle/upstart/puma-manager.conf +31 -0
  155. data/tools/jungle/upstart/puma.conf +69 -0
  156. data/tools/trickletest.rb +45 -0
  157. metadata +297 -0
@@ -0,0 +1,112 @@
1
+ require 'puma/runner'
2
+ require 'puma/detect'
3
+ require 'puma/plugin'
4
+
5
+ module Puma
6
+ class Single < Runner
7
+ def stats
8
+ b = @server.backlog
9
+ r = @server.running
10
+ %Q!{ "backlog": #{b}, "running": #{r} }!
11
+ end
12
+
13
+ def restart
14
+ @server.begin_restart
15
+ end
16
+
17
+ def stop
18
+ @server.stop false
19
+ end
20
+
21
+ def halt
22
+ @server.halt
23
+ end
24
+
25
+ def stop_blocked
26
+ log "- Gracefully stopping, waiting for requests to finish"
27
+ @control.stop(true) if @control
28
+ @server.stop(true)
29
+ end
30
+
31
+ def jruby_daemon?
32
+ daemon? and Puma.jruby?
33
+ end
34
+
35
+ def jruby_daemon_start
36
+ require 'puma/jruby_restart'
37
+ JRubyRestart.daemon_start(@restart_dir, @launcher.restart_args)
38
+ end
39
+
40
+ def run
41
+ already_daemon = false
42
+
43
+ if jruby_daemon?
44
+ require 'puma/jruby_restart'
45
+
46
+ if JRubyRestart.daemon?
47
+ # load and bind before redirecting IO so errors show up on stdout/stderr
48
+ load_and_bind
49
+ redirect_io
50
+ end
51
+
52
+ already_daemon = JRubyRestart.daemon_init
53
+ end
54
+
55
+ output_header "single"
56
+
57
+ if jruby_daemon?
58
+ if already_daemon
59
+ JRubyRestart.perm_daemonize
60
+ else
61
+ pid = nil
62
+
63
+ Signal.trap "SIGUSR2" do
64
+ log "* Started new process #{pid} as daemon..."
65
+
66
+ # Must use exit! so we don't unwind and run the ensures
67
+ # that will be run by the new child (such as deleting the
68
+ # pidfile)
69
+ exit!(true)
70
+ end
71
+
72
+ Signal.trap "SIGCHLD" do
73
+ log "! Error starting new process as daemon, exiting"
74
+ exit 1
75
+ end
76
+
77
+ jruby_daemon_start
78
+ sleep
79
+ end
80
+ else
81
+ if daemon?
82
+ log "* Daemonizing..."
83
+ Process.daemon(true)
84
+ redirect_io
85
+ end
86
+
87
+ load_and_bind
88
+ end
89
+
90
+ Plugins.fire_background
91
+
92
+ @launcher.write_state
93
+
94
+ start_control
95
+
96
+ @server = server = start_server
97
+
98
+ unless daemon?
99
+ log "Use Ctrl-C to stop"
100
+ redirect_io
101
+ end
102
+
103
+ @launcher.events.fire_on_booted!
104
+
105
+ begin
106
+ server.run.join
107
+ rescue Interrupt
108
+ # Swallow it
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,29 @@
1
+ require 'yaml'
2
+
3
+ module Puma
4
+ class StateFile
5
+ def initialize
6
+ @options = {}
7
+ end
8
+
9
+ def save(path)
10
+ File.write path, YAML.dump(@options)
11
+ end
12
+
13
+ def load(path)
14
+ @options = YAML.load File.read(path)
15
+ end
16
+
17
+ FIELDS = %w!control_url control_auth_token pid!
18
+
19
+ FIELDS.each do |f|
20
+ define_method f do
21
+ @options[f]
22
+ end
23
+
24
+ define_method "#{f}=" do |v|
25
+ @options[f] = v
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,39 @@
1
+ module Puma
2
+ class TCPLogger
3
+ def initialize(logger, app, quiet=false)
4
+ @logger = logger
5
+ @app = app
6
+ @quiet = quiet
7
+ end
8
+
9
+ FORMAT = "%s - %s"
10
+
11
+ def log(who, str)
12
+ now = Time.now.strftime("%d/%b/%Y %H:%M:%S")
13
+
14
+ log_str = "#{now} - #{who} - #{str}"
15
+
16
+ case @logger
17
+ when IO
18
+ @logger.puts log_str
19
+ when Events
20
+ @logger.log log_str
21
+ end
22
+ end
23
+
24
+ def call(env, socket)
25
+ who = env[Const::REMOTE_ADDR]
26
+ log who, "connected" unless @quiet
27
+
28
+ env['log'] = lambda { |str| log(who, str) }
29
+
30
+ begin
31
+ @app.call env, socket
32
+ rescue Object => e
33
+ log who, "exception: #{e.message} (#{e.class})"
34
+ else
35
+ log who, "disconnected" unless @quiet
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,297 @@
1
+ require 'thread'
2
+
3
+ module Puma
4
+ # A simple thread pool management object.
5
+ #
6
+ class ThreadPool
7
+ class ForceShutdown < RuntimeError
8
+ end
9
+
10
+ # How long, after raising the ForceShutdown of a thread during
11
+ # forced shutdown mode, to wait for the thread to try and finish
12
+ # up its work before leaving the thread to die on the vine.
13
+ SHUTDOWN_GRACE_TIME = 5 # seconds
14
+
15
+ # Maintain a minimum of +min+ and maximum of +max+ threads
16
+ # in the pool.
17
+ #
18
+ # The block passed is the work that will be performed in each
19
+ # thread.
20
+ #
21
+ def initialize(min, max, *extra, &block)
22
+ @not_empty = ConditionVariable.new
23
+ @not_full = ConditionVariable.new
24
+ @mutex = Mutex.new
25
+
26
+ @todo = []
27
+
28
+ @spawned = 0
29
+ @waiting = 0
30
+
31
+ @min = Integer(min)
32
+ @max = Integer(max)
33
+ @block = block
34
+ @extra = extra
35
+
36
+ @shutdown = false
37
+
38
+ @trim_requested = 0
39
+
40
+ @workers = []
41
+
42
+ @auto_trim = nil
43
+ @reaper = nil
44
+
45
+ @mutex.synchronize do
46
+ @min.times { spawn_thread }
47
+ end
48
+
49
+ @clean_thread_locals = false
50
+ end
51
+
52
+ attr_reader :spawned, :trim_requested
53
+ attr_accessor :clean_thread_locals
54
+
55
+ def self.clean_thread_locals
56
+ Thread.current.keys.each do |key|
57
+ Thread.current[key] = nil unless key == :__recursive_key__
58
+ end
59
+ end
60
+
61
+ # How many objects have yet to be processed by the pool?
62
+ #
63
+ def backlog
64
+ @mutex.synchronize { @todo.size }
65
+ end
66
+
67
+ # :nodoc:
68
+ #
69
+ # Must be called with @mutex held!
70
+ #
71
+ def spawn_thread
72
+ @spawned += 1
73
+
74
+ th = Thread.new do
75
+ # Thread name is new in Ruby 2.3
76
+ Thread.current.name = 'puma %03i' % @spawned if Thread.current.respond_to?(:name=)
77
+ todo = @todo
78
+ block = @block
79
+ mutex = @mutex
80
+ not_empty = @not_empty
81
+ not_full = @not_full
82
+
83
+ extra = @extra.map { |i| i.new }
84
+
85
+ while true
86
+ work = nil
87
+
88
+ continue = true
89
+
90
+ mutex.synchronize do
91
+ while todo.empty?
92
+ if @trim_requested > 0
93
+ @trim_requested -= 1
94
+ continue = false
95
+ not_full.signal
96
+ break
97
+ end
98
+
99
+ if @shutdown
100
+ continue = false
101
+ break
102
+ end
103
+
104
+ @waiting += 1
105
+ not_full.signal
106
+ not_empty.wait mutex
107
+ @waiting -= 1
108
+ end
109
+
110
+ work = todo.shift if continue
111
+ end
112
+
113
+ break unless continue
114
+
115
+ if @clean_thread_locals
116
+ ThreadPool.clean_thread_locals
117
+ end
118
+
119
+ begin
120
+ block.call(work, *extra)
121
+ rescue Exception => e
122
+ STDERR.puts "Error reached top of thread-pool: #{e.message} (#{e.class})"
123
+ end
124
+ end
125
+
126
+ mutex.synchronize do
127
+ @spawned -= 1
128
+ @workers.delete th
129
+ end
130
+ end
131
+
132
+ @workers << th
133
+
134
+ th
135
+ end
136
+
137
+ private :spawn_thread
138
+
139
+ # Add +work+ to the todo list for a Thread to pickup and process.
140
+ def <<(work)
141
+ @mutex.synchronize do
142
+ if @shutdown
143
+ raise "Unable to add work while shutting down"
144
+ end
145
+
146
+ @todo << work
147
+
148
+ if @waiting < @todo.size and @spawned < @max
149
+ spawn_thread
150
+ end
151
+
152
+ @not_empty.signal
153
+ end
154
+ end
155
+
156
+ def wait_until_not_full
157
+ @mutex.synchronize do
158
+ until @todo.size - @waiting < @max - @spawned or @shutdown
159
+ @not_full.wait @mutex
160
+ end
161
+ end
162
+ end
163
+
164
+ # If too many threads are in the pool, tell one to finish go ahead
165
+ # and exit. If +force+ is true, then a trim request is requested
166
+ # even if all threads are being utilized.
167
+ #
168
+ def trim(force=false)
169
+ @mutex.synchronize do
170
+ if (force or @waiting > 0) and @spawned - @trim_requested > @min
171
+ @trim_requested += 1
172
+ @not_empty.signal
173
+ end
174
+ end
175
+ end
176
+
177
+ # If there are dead threads in the pool make them go away while decreasing
178
+ # spawned counter so that new healthy threads could be created again.
179
+ def reap
180
+ @mutex.synchronize do
181
+ dead_workers = @workers.reject(&:alive?)
182
+
183
+ dead_workers.each do |worker|
184
+ worker.kill
185
+ @spawned -= 1
186
+ end
187
+
188
+ @workers.delete_if do |w|
189
+ dead_workers.include?(w)
190
+ end
191
+ end
192
+ end
193
+
194
+ class AutoTrim
195
+ def initialize(pool, timeout)
196
+ @pool = pool
197
+ @timeout = timeout
198
+ @running = false
199
+ end
200
+
201
+ def start!
202
+ @running = true
203
+
204
+ @thread = Thread.new do
205
+ while @running
206
+ @pool.trim
207
+ sleep @timeout
208
+ end
209
+ end
210
+ end
211
+
212
+ def stop
213
+ @running = false
214
+ @thread.wakeup
215
+ end
216
+ end
217
+
218
+ def auto_trim!(timeout=30)
219
+ @auto_trim = AutoTrim.new(self, timeout)
220
+ @auto_trim.start!
221
+ end
222
+
223
+ class Reaper
224
+ def initialize(pool, timeout)
225
+ @pool = pool
226
+ @timeout = timeout
227
+ @running = false
228
+ end
229
+
230
+ def start!
231
+ @running = true
232
+
233
+ @thread = Thread.new do
234
+ while @running
235
+ @pool.reap
236
+ sleep @timeout
237
+ end
238
+ end
239
+ end
240
+
241
+ def stop
242
+ @running = false
243
+ @thread.wakeup
244
+ end
245
+ end
246
+
247
+ def auto_reap!(timeout=5)
248
+ @reaper = Reaper.new(self, timeout)
249
+ @reaper.start!
250
+ end
251
+
252
+ # Tell all threads in the pool to exit and wait for them to finish.
253
+ #
254
+ def shutdown(timeout=-1)
255
+ threads = @mutex.synchronize do
256
+ @shutdown = true
257
+ @not_empty.broadcast
258
+ @not_full.broadcast
259
+
260
+ @auto_trim.stop if @auto_trim
261
+ @reaper.stop if @reaper
262
+ # dup workers so that we join them all safely
263
+ @workers.dup
264
+ end
265
+
266
+ if timeout == -1
267
+ # Wait for threads to finish without force shutdown.
268
+ threads.each(&:join)
269
+ else
270
+ # Wait for threads to finish after n attempts (+timeout+).
271
+ # If threads are still running, it will forcefully kill them.
272
+ timeout.times do
273
+ threads.delete_if do |t|
274
+ t.join 1
275
+ end
276
+
277
+ if threads.empty?
278
+ break
279
+ else
280
+ sleep 1
281
+ end
282
+ end
283
+
284
+ threads.each do |t|
285
+ t.raise ForceShutdown
286
+ end
287
+
288
+ threads.each do |t|
289
+ t.join SHUTDOWN_GRACE_TIME
290
+ end
291
+ end
292
+
293
+ @spawned = 0
294
+ @workers = []
295
+ end
296
+ end
297
+ end