puma 2.3.0 → 2.3.1

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.

data/Gemfile CHANGED
@@ -2,6 +2,7 @@ source "http://rubygems.org"
2
2
 
3
3
  gem "hoe"
4
4
  gem "hoe-git"
5
+ gem "hoe-ignore"
5
6
  gem "rdoc"
6
7
  gem "rake-compiler"
7
8
  gem "rack"
@@ -1,3 +1,13 @@
1
+ === 2.3.1 / 2013-07-06
2
+
3
+ * 2 bug fixes:
4
+
5
+ * Include the right files in the Manifest.
6
+ * Disable inheriting connections on restart on windows. Fixes #166
7
+
8
+ * 1 doc change:
9
+ * Better document some platform constraints
10
+
1
11
  === 2.3.0 / 2013-07-05
2
12
 
3
13
  * 1 major bug fix:
@@ -31,6 +31,7 @@ lib/puma/binder.rb
31
31
  lib/puma/capistrano.rb
32
32
  lib/puma/cli.rb
33
33
  lib/puma/client.rb
34
+ lib/puma/cluster.rb
34
35
  lib/puma/compat.rb
35
36
  lib/puma/configuration.rb
36
37
  lib/puma/const.rb
@@ -47,14 +48,18 @@ lib/puma/null_io.rb
47
48
  lib/puma/rack_default.rb
48
49
  lib/puma/rack_patch.rb
49
50
  lib/puma/reactor.rb
51
+ lib/puma/runner.rb
50
52
  lib/puma/server.rb
53
+ lib/puma/single.rb
51
54
  lib/puma/thread_pool.rb
52
55
  lib/puma/util.rb
53
56
  lib/rack/handler/puma.rb
54
57
  puma.gemspec
58
+ tools/jungle/README.md
55
59
  tools/jungle/init.d/README.md
56
60
  tools/jungle/init.d/puma
57
61
  tools/jungle/init.d/run-puma
58
62
  tools/jungle/upstart/README.md
59
63
  tools/jungle/upstart/puma-manager.conf
60
64
  tools/jungle/upstart/puma.conf
65
+ tools/trickletest.rb
data/README.md CHANGED
@@ -175,6 +175,14 @@ Puma isn't able to understand all the resources that your app may use, so it pro
175
175
 
176
176
  You should place code to close global log files, redis connections, etc in this block so that their file descriptors don't leak into the restarted process. Failure to do so will result in slowly running out of descriptors and eventually obscure crashes as the server is restart many times.
177
177
 
178
+ ### Platform Constaints
179
+
180
+ Because of various platforms not being implement certain things, the following differences occur when puma is used on different platforms:
181
+
182
+ * On JRuby and Windows, server sockets are not seamless on restart, they must be closed and reopened. These platforms have no way to pass descriptors into a new process that is exposed to ruby.
183
+ * On Windows, daemon mode is not supported due to a lack of fork(2).
184
+ * On JRuby and Windows, cluster mode is not supported due to a lack of fork(2).
185
+
178
186
  ## pumactl
179
187
 
180
188
  If you start puma with `-S some/path` then you can pass that same path to the `pumactl` program to control your server. For instance:
data/Rakefile CHANGED
@@ -5,6 +5,7 @@ require "rake/javaextensiontask"
5
5
  IS_JRUBY = defined?(RUBY_ENGINE) ? RUBY_ENGINE == "jruby" : false
6
6
 
7
7
  Hoe.plugin :git
8
+ Hoe.plugin :ignore
8
9
 
9
10
  HOE = Hoe.spec "puma" do
10
11
  self.rubyforge_name = 'puma'
@@ -24,6 +25,8 @@ HOE = Hoe.spec "puma" do
24
25
  extra_dev_deps << ["rake-compiler", "~> 0.8.0"]
25
26
  end
26
27
 
28
+ task :prerelease => [:clobber, :check_manifest, :test]
29
+
27
30
  # hoe/test and rake-compiler don't seem to play well together, so disable
28
31
  # hoe/test's .gemtest touch file thingy for now
29
32
  HOE.spec.files -= [".gemtest"]
@@ -365,6 +365,26 @@ module Puma
365
365
 
366
366
  require 'puma/jruby_restart'
367
367
  JRubyRestart.chdir_exec(@restart_dir, restart_args)
368
+
369
+ elsif windows?
370
+ @binder.listeners.each_with_index do |(str,io),i|
371
+ io.close
372
+
373
+ # We have to unlink a unix socket path that's not being used
374
+ uri = URI.parse str
375
+ if uri.scheme == "unix"
376
+ path = "#{uri.host}#{uri.path}"
377
+ File.unlink path
378
+ end
379
+ end
380
+
381
+ argv = restart_args
382
+
383
+ Dir.chdir @restart_dir
384
+
385
+ argv += [redirects] unless RUBY_VERSION < '1.9'
386
+ Kernel.exec(*argv)
387
+
368
388
  else
369
389
  redirects = {:close_others => true}
370
390
  @binder.listeners.each_with_index do |(l,io),i|
@@ -0,0 +1,313 @@
1
+ require 'puma/runner'
2
+
3
+ module Puma
4
+ class Cluster < Runner
5
+ def initialize(cli)
6
+ super cli
7
+
8
+ @phase = 0
9
+ @workers = []
10
+
11
+ @phased_state = :idle
12
+ @phased_restart = false
13
+ end
14
+
15
+ def stop_workers
16
+ log "- Gracefully shutting down workers..."
17
+ @workers.each { |x| x.term }
18
+
19
+ begin
20
+ Process.waitall
21
+ rescue Interrupt
22
+ log "! Cancelled waiting for workers"
23
+ end
24
+ end
25
+
26
+ def start_phased_restart
27
+ @phase += 1
28
+ log "- Starting phased worker restart, phase: #{@phase}"
29
+ end
30
+
31
+ class Worker
32
+ def initialize(pid, phase)
33
+ @pid = pid
34
+ @phase = phase
35
+ @stage = :started
36
+ end
37
+
38
+ attr_reader :pid, :phase
39
+
40
+ def booted?
41
+ @stage == :booted
42
+ end
43
+
44
+ def boot!
45
+ @stage = :booted
46
+ end
47
+
48
+ def term
49
+ begin
50
+ Process.kill "TERM", @pid
51
+ rescue Errno::ESRCH
52
+ end
53
+ end
54
+ end
55
+
56
+ def spawn_workers
57
+ diff = @options[:workers] - @workers.size
58
+
59
+ upgrade = (@phased_state == :waiting)
60
+
61
+ master = Process.pid
62
+
63
+ diff.times do
64
+ pid = fork { worker(upgrade, master) }
65
+ @cli.debug "Spawned worker: #{pid}"
66
+ @workers << Worker.new(pid, @phase)
67
+ end
68
+
69
+ if diff > 0
70
+ @phased_state = :idle
71
+ end
72
+ end
73
+
74
+ def all_workers_booted?
75
+ @workers.count { |w| !w.booted? } == 0
76
+ end
77
+
78
+ def check_workers
79
+ while @workers.any?
80
+ pid = Process.waitpid(-1, Process::WNOHANG)
81
+ break unless pid
82
+
83
+ @workers.delete_if { |w| w.pid == pid }
84
+ end
85
+
86
+ spawn_workers
87
+
88
+ if @phased_state == :idle && all_workers_booted?
89
+ # If we're running at proper capacity, check to see if
90
+ # we need to phase any workers out (which will restart
91
+ # in the right phase).
92
+ #
93
+ w = @workers.find { |x| x.phase != @phase }
94
+
95
+ if w
96
+ @phased_state = :waiting
97
+ log "- Stopping #{w.pid} for phased upgrade..."
98
+ w.term
99
+ end
100
+ end
101
+ end
102
+
103
+ def wakeup!
104
+ begin
105
+ @wakeup.write "!" unless @wakeup.closed?
106
+ rescue SystemCallError, IOError
107
+ end
108
+ end
109
+
110
+ def worker(upgrade, master)
111
+ $0 = "puma: cluster worker: #{master}"
112
+ Signal.trap "SIGINT", "IGNORE"
113
+
114
+ @master_read.close
115
+ @suicide_pipe.close
116
+
117
+ Thread.new do
118
+ IO.select [@check_pipe]
119
+ log "! Detected parent died, dying"
120
+ exit! 1
121
+ end
122
+
123
+ # Be sure to change the directory again before loading
124
+ # the app. This way we can pick up new code.
125
+ if upgrade
126
+ if dir = @options[:worker_directory]
127
+ log "+ Changing to #{dir}"
128
+ Dir.chdir dir
129
+ end
130
+ end
131
+
132
+ # Invoke any worker boot hooks so they can get
133
+ # things in shape before booting the app.
134
+ hooks = @options[:worker_boot]
135
+ hooks.each { |h| h.call }
136
+
137
+ server = start_server
138
+
139
+ Signal.trap "SIGTERM" do
140
+ server.stop
141
+ end
142
+
143
+ begin
144
+ @worker_write << "b#{Process.pid}\n"
145
+ rescue SystemCallError, IOError
146
+ STDERR.puts "Master seems to have exitted, exitting."
147
+ return
148
+ end
149
+
150
+ server.run.join
151
+
152
+ ensure
153
+ @worker_write.close
154
+ end
155
+
156
+ def restart
157
+ @restart = true
158
+ stop
159
+ end
160
+
161
+ def phased_restart
162
+ return false if @options[:preload_app]
163
+
164
+ @phased_restart = true
165
+ wakeup!
166
+
167
+ true
168
+ end
169
+
170
+ def stop
171
+ @status = :stop
172
+ wakeup!
173
+ end
174
+
175
+ def stop_blocked
176
+ @status = :stop if @status == :run
177
+ wakeup!
178
+ Process.waitall
179
+ end
180
+
181
+ def halt
182
+ @status = :halt
183
+ wakeup!
184
+ end
185
+
186
+ def stats
187
+ %Q!{ "workers": #{@workers.size}, "phase": #{@phase} }!
188
+ end
189
+
190
+ def preload?
191
+ @options[:preload_app]
192
+ end
193
+
194
+ def run
195
+ @status = :run
196
+
197
+ output_header "cluster"
198
+
199
+ log "* Process workers: #{@options[:workers]}"
200
+
201
+ if preload?
202
+ log "* Preloading application"
203
+ load_and_bind
204
+ else
205
+ log "* Phased restart available"
206
+
207
+ unless @cli.config.app_configured?
208
+ error "No application configured, nothing to run"
209
+ exit 1
210
+ end
211
+
212
+ @cli.binder.parse @options[:binds], self
213
+ end
214
+
215
+ read, @wakeup = Puma::Util.pipe
216
+
217
+ Signal.trap "SIGCHLD" do
218
+ wakeup!
219
+ end
220
+
221
+ master_pid = Process.pid
222
+
223
+ Signal.trap "SIGTERM" do
224
+ # The worker installs their own SIGTERM when booted.
225
+ # Until then, this is run by the worker and the worker
226
+ # should just exit if they get it.
227
+ if Process.pid != master_pid
228
+ log "Early termination of worker"
229
+ exit! 0
230
+ else
231
+ stop
232
+ end
233
+ end
234
+
235
+ if preload?
236
+ Signal.trap "SIGUSR1" do
237
+ log "App preloaded, phased restart unavailable"
238
+ end
239
+ else
240
+ Signal.trap "SIGUSR1" do
241
+ phased_restart
242
+ end
243
+ end
244
+
245
+ # Used by the workers to detect if the master process dies.
246
+ # If select says that @check_pipe is ready, it's because the
247
+ # master has exited and @suicide_pipe has been automatically
248
+ # closed.
249
+ #
250
+ @check_pipe, @suicide_pipe = Puma::Util.pipe
251
+
252
+ if daemon?
253
+ log "* Daemonizing..."
254
+ Process.daemon(true)
255
+ else
256
+ log "Use Ctrl-C to stop"
257
+ end
258
+
259
+ redirect_io
260
+
261
+ @cli.write_state
262
+
263
+ @master_read, @worker_write = read, @wakeup
264
+ spawn_workers
265
+
266
+ Signal.trap "SIGINT" do
267
+ stop
268
+ end
269
+
270
+ @cli.events.fire_on_booted!
271
+
272
+ begin
273
+ while @status == :run
274
+ begin
275
+ res = IO.select([read], nil, nil, 5)
276
+
277
+ if res
278
+ req = read.read_nonblock(1)
279
+
280
+ if req == "b"
281
+ pid = read.gets.to_i
282
+ w = @workers.find { |x| x.pid == pid }
283
+ if w
284
+ w.boot!
285
+ log "- Worker #{pid} booted, phase: #{w.phase}"
286
+ else
287
+ log "! Out-of-sync worker list, no #{pid} worker"
288
+ end
289
+ end
290
+ end
291
+
292
+ if @phased_restart
293
+ start_phased_restart
294
+ @phased_restart = false
295
+ end
296
+
297
+ check_workers
298
+
299
+ rescue Interrupt
300
+ @status = :stop
301
+ end
302
+ end
303
+
304
+ stop_workers unless @status == :halt
305
+ ensure
306
+ @check_pipe.close
307
+ @suicide_pipe.close
308
+ read.close
309
+ @wakeup.close
310
+ end
311
+ end
312
+ end
313
+ end
@@ -28,7 +28,7 @@ module Puma
28
28
  # too taxing on performance.
29
29
  module Const
30
30
 
31
- PUMA_VERSION = VERSION = "2.3.0".freeze
31
+ PUMA_VERSION = VERSION = "2.3.1".freeze
32
32
  CODE_NAME = "Delicious Thin Mints"
33
33
 
34
34
  FAST_TRACK_KA_TIMEOUT = 0.2
@@ -0,0 +1,90 @@
1
+ module Puma
2
+ class Runner
3
+ def initialize(cli)
4
+ @cli = cli
5
+ @options = cli.options
6
+ @app = nil
7
+ end
8
+
9
+ def daemon?
10
+ @options[:daemon]
11
+ end
12
+
13
+ def development?
14
+ @options[:environment] == "development"
15
+ end
16
+
17
+ def log(str)
18
+ @cli.log str
19
+ end
20
+
21
+ def error(str)
22
+ @cli.error str
23
+ end
24
+
25
+ def output_header(mode)
26
+ min_t = @options[:min_threads]
27
+ max_t = @options[:max_threads]
28
+
29
+ log "Puma starting in #{mode} mode..."
30
+ log "* Version #{Puma::Const::PUMA_VERSION}, codename: #{Puma::Const::CODE_NAME}"
31
+ log "* Min threads: #{min_t}, max threads: #{max_t}"
32
+ log "* Environment: #{ENV['RACK_ENV']}"
33
+ end
34
+
35
+ def redirect_io
36
+ stdout = @options[:redirect_stdout]
37
+ stderr = @options[:redirect_stderr]
38
+ append = @options[:redirect_append]
39
+
40
+ if stdout
41
+ STDOUT.reopen stdout, (append ? "a" : "w")
42
+ STDOUT.sync = true
43
+ STDOUT.puts "=== puma startup: #{Time.now} ==="
44
+ end
45
+
46
+ if stderr
47
+ STDERR.reopen stderr, (append ? "a" : "w")
48
+ STDERR.sync = true
49
+ STDERR.puts "=== puma startup: #{Time.now} ==="
50
+ end
51
+ end
52
+
53
+ def load_and_bind
54
+ unless @cli.config.app_configured?
55
+ error "No application configured, nothing to run"
56
+ exit 1
57
+ end
58
+
59
+ # Load the app before we daemonize.
60
+ begin
61
+ @app = @cli.config.app
62
+ rescue Exception => e
63
+ log "! Unable to load application"
64
+ raise e
65
+ end
66
+
67
+ @cli.binder.parse @options[:binds], self
68
+ end
69
+
70
+ def app
71
+ @app ||= @cli.config.app
72
+ end
73
+
74
+ def start_server
75
+ min_t = @options[:min_threads]
76
+ max_t = @options[:max_threads]
77
+
78
+ server = Puma::Server.new app, @cli.events
79
+ server.min_threads = min_t
80
+ server.max_threads = max_t
81
+ server.inherit_binder @cli.binder
82
+
83
+ unless development?
84
+ server.leak_stack_on_error = false
85
+ end
86
+
87
+ server
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,88 @@
1
+ require 'puma/runner'
2
+
3
+ module Puma
4
+ class Single < Runner
5
+ def stats
6
+ b = @server.backlog
7
+ r = @server.running
8
+ %Q!{ "backlog": #{b}, "running": #{r} }!
9
+ end
10
+
11
+ def restart
12
+ @server.begin_restart
13
+ end
14
+
15
+ def stop
16
+ @server.stop false
17
+ end
18
+
19
+ def halt
20
+ @server.halt
21
+ end
22
+
23
+ def stop_blocked
24
+ log "- Gracefully stopping, waiting for requests to finish"
25
+ @server.stop(true)
26
+ end
27
+
28
+ def jruby_daemon?
29
+ daemon? and @cli.jruby?
30
+ end
31
+
32
+ def run
33
+ already_daemon = false
34
+
35
+ if jruby_daemon?
36
+ require 'puma/jruby_restart'
37
+
38
+ if JRubyRestart.daemon?
39
+ # load and bind before redirecting IO so errors show up on stdout/stderr
40
+ load_and_bind
41
+ end
42
+
43
+ already_daemon = JRubyRestart.daemon_init
44
+ end
45
+
46
+ output_header "single"
47
+
48
+ if jruby_daemon?
49
+ unless already_daemon
50
+ pid = nil
51
+
52
+ Signal.trap "SIGUSR2" do
53
+ log "* Started new process #{pid} as daemon..."
54
+ exit
55
+ end
56
+
57
+ pid = @cli.jruby_daemon_start
58
+ sleep
59
+ end
60
+ else
61
+ load_and_bind
62
+
63
+ if daemon?
64
+ log "* Daemonizing..."
65
+ Process.daemon(true)
66
+ end
67
+ end
68
+
69
+ @cli.write_state
70
+
71
+ @server = server = start_server
72
+
73
+ unless @options[:daemon]
74
+ log "Use Ctrl-C to stop"
75
+ end
76
+
77
+ redirect_io
78
+
79
+ @cli.events.fire_on_booted!
80
+
81
+ begin
82
+ server.run.join
83
+ rescue Interrupt
84
+ # Swallow it
85
+ end
86
+ end
87
+ end
88
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "puma"
5
- s.version = "2.3.0"
5
+ s.version = "2.3.1"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Evan Phoenix"]
@@ -11,8 +11,8 @@ Gem::Specification.new do |s|
11
11
  s.email = ["evan@phx.io"]
12
12
  s.executables = ["puma", "pumactl"]
13
13
  s.extensions = ["ext/puma_http11/extconf.rb"]
14
- s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.md", "docs/config.md", "docs/nginx.md", "tools/jungle/init.d/README.md", "tools/jungle/upstart/README.md"]
15
- s.files = ["COPYING", "Gemfile", "History.txt", "LICENSE", "Manifest.txt", "README.md", "Rakefile", "TODO", "bin/puma", "bin/pumactl", "docs/config.md", "docs/nginx.md", "ext/puma_http11/PumaHttp11Service.java", "ext/puma_http11/ext_help.h", "ext/puma_http11/extconf.rb", "ext/puma_http11/http11_parser.c", "ext/puma_http11/http11_parser.h", "ext/puma_http11/http11_parser.java.rl", "ext/puma_http11/http11_parser.rl", "ext/puma_http11/http11_parser_common.rl", "ext/puma_http11/io_buffer.c", "ext/puma_http11/mini_ssl.c", "ext/puma_http11/org/jruby/puma/Http11.java", "ext/puma_http11/org/jruby/puma/Http11Parser.java", "ext/puma_http11/org/jruby/puma/MiniSSL.java", "ext/puma_http11/puma_http11.c", "lib/puma.rb", "lib/puma/accept_nonblock.rb", "lib/puma/app/status.rb", "lib/puma/binder.rb", "lib/puma/capistrano.rb", "lib/puma/cli.rb", "lib/puma/client.rb", "lib/puma/compat.rb", "lib/puma/configuration.rb", "lib/puma/const.rb", "lib/puma/control_cli.rb", "lib/puma/daemon_ext.rb", "lib/puma/delegation.rb", "lib/puma/detect.rb", "lib/puma/events.rb", "lib/puma/io_buffer.rb", "lib/puma/java_io_buffer.rb", "lib/puma/jruby_restart.rb", "lib/puma/minissl.rb", "lib/puma/null_io.rb", "lib/puma/rack_default.rb", "lib/puma/rack_patch.rb", "lib/puma/reactor.rb", "lib/puma/server.rb", "lib/puma/thread_pool.rb", "lib/puma/util.rb", "lib/rack/handler/puma.rb", "puma.gemspec", "tools/jungle/init.d/README.md", "tools/jungle/init.d/puma", "tools/jungle/init.d/run-puma", "tools/jungle/upstart/README.md", "tools/jungle/upstart/puma-manager.conf", "tools/jungle/upstart/puma.conf", "test/test_app_status.rb", "test/test_cli.rb", "test/test_config.rb", "test/test_http10.rb", "test/test_http11.rb", "test/test_integration.rb", "test/test_iobuffer.rb", "test/test_minissl.rb", "test/test_null_io.rb", "test/test_persistent.rb", "test/test_puma_server.rb", "test/test_rack_handler.rb", "test/test_rack_server.rb", "test/test_thread_pool.rb", "test/test_unix_socket.rb", "test/test_ws.rb"]
14
+ s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.md", "docs/config.md", "docs/nginx.md", "tools/jungle/README.md", "tools/jungle/init.d/README.md", "tools/jungle/upstart/README.md"]
15
+ s.files = ["COPYING", "Gemfile", "History.txt", "LICENSE", "Manifest.txt", "README.md", "Rakefile", "TODO", "bin/puma", "bin/pumactl", "docs/config.md", "docs/nginx.md", "ext/puma_http11/PumaHttp11Service.java", "ext/puma_http11/ext_help.h", "ext/puma_http11/extconf.rb", "ext/puma_http11/http11_parser.c", "ext/puma_http11/http11_parser.h", "ext/puma_http11/http11_parser.java.rl", "ext/puma_http11/http11_parser.rl", "ext/puma_http11/http11_parser_common.rl", "ext/puma_http11/io_buffer.c", "ext/puma_http11/mini_ssl.c", "ext/puma_http11/org/jruby/puma/Http11.java", "ext/puma_http11/org/jruby/puma/Http11Parser.java", "ext/puma_http11/org/jruby/puma/MiniSSL.java", "ext/puma_http11/puma_http11.c", "lib/puma.rb", "lib/puma/accept_nonblock.rb", "lib/puma/app/status.rb", "lib/puma/binder.rb", "lib/puma/capistrano.rb", "lib/puma/cli.rb", "lib/puma/client.rb", "lib/puma/cluster.rb", "lib/puma/compat.rb", "lib/puma/configuration.rb", "lib/puma/const.rb", "lib/puma/control_cli.rb", "lib/puma/daemon_ext.rb", "lib/puma/delegation.rb", "lib/puma/detect.rb", "lib/puma/events.rb", "lib/puma/io_buffer.rb", "lib/puma/java_io_buffer.rb", "lib/puma/jruby_restart.rb", "lib/puma/minissl.rb", "lib/puma/null_io.rb", "lib/puma/rack_default.rb", "lib/puma/rack_patch.rb", "lib/puma/reactor.rb", "lib/puma/runner.rb", "lib/puma/server.rb", "lib/puma/single.rb", "lib/puma/thread_pool.rb", "lib/puma/util.rb", "lib/rack/handler/puma.rb", "puma.gemspec", "tools/jungle/README.md", "tools/jungle/init.d/README.md", "tools/jungle/init.d/puma", "tools/jungle/init.d/run-puma", "tools/jungle/upstart/README.md", "tools/jungle/upstart/puma-manager.conf", "tools/jungle/upstart/puma.conf", "tools/trickletest.rb", "test/test_app_status.rb", "test/test_cli.rb", "test/test_config.rb", "test/test_http10.rb", "test/test_http11.rb", "test/test_integration.rb", "test/test_iobuffer.rb", "test/test_minissl.rb", "test/test_null_io.rb", "test/test_persistent.rb", "test/test_puma_server.rb", "test/test_rack_handler.rb", "test/test_rack_server.rb", "test/test_thread_pool.rb", "test/test_unix_socket.rb", "test/test_ws.rb"]
16
16
  s.homepage = "http://puma.io"
17
17
  s.rdoc_options = ["--main", "README.md"]
18
18
  s.require_paths = ["lib"]
@@ -0,0 +1,9 @@
1
+ # Puma as a service
2
+
3
+ ## Init.d
4
+
5
+ See `/tools/jungle/init.d` for tools to use with init.d and start-stop-daemon.
6
+
7
+ ## Upstart
8
+
9
+ See `/tools/jungle/upstart` for Ubuntu's upstart scripts.
@@ -0,0 +1,45 @@
1
+ require 'socket'
2
+ require 'stringio'
3
+
4
+ def do_test(st, chunk)
5
+ s = TCPSocket.new('127.0.0.1',ARGV[0].to_i);
6
+ req = StringIO.new(st)
7
+ nout = 0
8
+ randstop = rand(st.length / 10)
9
+ STDERR.puts "stopping after: #{randstop}"
10
+
11
+ begin
12
+ while data = req.read(chunk)
13
+ nout += s.write(data)
14
+ s.flush
15
+ sleep 0.1
16
+ if nout > randstop
17
+ STDERR.puts "BANG! after #{nout} bytes."
18
+ break
19
+ end
20
+ end
21
+ rescue Object => e
22
+ STDERR.puts "ERROR: #{e}"
23
+ ensure
24
+ s.close
25
+ end
26
+ end
27
+
28
+ content = "-" * (1024 * 240)
29
+ st = "GET / HTTP/1.1\r\nHost: www.zedshaw.com\r\nContent-Type: text/plain\r\nContent-Length: #{content.length}\r\n\r\n#{content}"
30
+
31
+ puts "length: #{content.length}"
32
+
33
+ threads = []
34
+ ARGV[1].to_i.times do
35
+ t = Thread.new do
36
+ size = 100
37
+ puts ">>>> #{size} sized chunks"
38
+ do_test(st, size)
39
+ end
40
+
41
+ t.abort_on_exception = true
42
+ threads << t
43
+ end
44
+
45
+ threads.each {|t| t.join}
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: puma
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.0
4
+ version: 2.3.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -98,6 +98,7 @@ extra_rdoc_files:
98
98
  - README.md
99
99
  - docs/config.md
100
100
  - docs/nginx.md
101
+ - tools/jungle/README.md
101
102
  - tools/jungle/init.d/README.md
102
103
  - tools/jungle/upstart/README.md
103
104
  files:
@@ -134,6 +135,7 @@ files:
134
135
  - lib/puma/capistrano.rb
135
136
  - lib/puma/cli.rb
136
137
  - lib/puma/client.rb
138
+ - lib/puma/cluster.rb
137
139
  - lib/puma/compat.rb
138
140
  - lib/puma/configuration.rb
139
141
  - lib/puma/const.rb
@@ -150,17 +152,21 @@ files:
150
152
  - lib/puma/rack_default.rb
151
153
  - lib/puma/rack_patch.rb
152
154
  - lib/puma/reactor.rb
155
+ - lib/puma/runner.rb
153
156
  - lib/puma/server.rb
157
+ - lib/puma/single.rb
154
158
  - lib/puma/thread_pool.rb
155
159
  - lib/puma/util.rb
156
160
  - lib/rack/handler/puma.rb
157
161
  - puma.gemspec
162
+ - tools/jungle/README.md
158
163
  - tools/jungle/init.d/README.md
159
164
  - tools/jungle/init.d/puma
160
165
  - tools/jungle/init.d/run-puma
161
166
  - tools/jungle/upstart/README.md
162
167
  - tools/jungle/upstart/puma-manager.conf
163
168
  - tools/jungle/upstart/puma.conf
169
+ - tools/trickletest.rb
164
170
  - test/test_app_status.rb
165
171
  - test/test_cli.rb
166
172
  - test/test_config.rb