puma-simon 3.7.1

Sign up to get free protection for your applications and to get access to all the features.
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