Hello community,

here is the log from the commit of package rubygem-puma for openSUSE:Factory 
checked in at 2018-07-18 22:54:42
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/rubygem-puma (Old)
 and      /work/SRC/openSUSE:Factory/.rubygem-puma.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "rubygem-puma"

Wed Jul 18 22:54:42 2018 rev:30 rq:622809 version:3.12.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/rubygem-puma/rubygem-puma.changes        
2018-02-12 10:13:49.704503267 +0100
+++ /work/SRC/openSUSE:Factory/.rubygem-puma.new/rubygem-puma.changes   
2018-07-18 22:55:43.466605825 +0200
@@ -1,0 +2,50 @@
+Fri Jul 13 17:15:17 UTC 2018 - [email protected]
+
+- updated to version 3.12.0
+ see installed History.md
+
+  ## 3.12.0 / 2018-07-13
+  
+  * 5 features:
+    * You can now specify which SSL ciphers the server should support, default 
is unchanged (#1478)
+    * The setting for Puma's `max_threads` is now in `Puma.stats` (#1604)
+    * Pool capacity is now in `Puma.stats` (#1579)
+    * Installs restricted to Ruby 2.2+ (#1506)
+    * `--control` is now deprecated in favor of `--control-url` (#1487)
+  
+  * 2 bugfixes:
+    * Workers will no longer accept more web requests than they have capacity 
to process. This prevents an issue where one worker would accept lots of 
requests while starving other workers (#1563)
+    * In a test env puma now emits the stack on an exception (#1557)
+
+-------------------------------------------------------------------
+Thu Apr 12 20:44:52 UTC 2018 - [email protected]
+
+- updated to version 3.11.4
+ see installed History.md
+
+  ## 3.11.4 / 2018-04-12
+  
+  * 2 features:
+    * Manage puma as a service using rc.d (#1529)
+    * Server stats are now available from a top level method (#1532)
+  * 5 bugfixes:
+    * Fix parsing CLI options (#1482)
+    * Order of stderr and stdout is made before redirecting to a log file 
(#1511)
+    * Init.d fix of `ps -p` to check if pid exists (#1545)
+    * Early hits bugfix (#1550)
+    * Purge interrupt queue when closing socket fails (#1553)
+
+-------------------------------------------------------------------
+Tue Mar 20 10:14:18 UTC 2018 - [email protected]
+
+- updated to version 3.11.3
+ see installed History.md
+
+  ## 3.11.3 / 2018-03-05
+  
+  * 3 bugfixes:
+    * Add closed? to MiniSSL::Socket for use in reactor (#1510)
+    * Handle EOFError at the toplevel of the server threads (#1524) (#1507)
+    * Deal with zero sized bodies when using SSL (#1483)
+
+-------------------------------------------------------------------

Old:
----
  puma-3.11.2.gem

New:
----
  puma-3.12.0.gem

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ rubygem-puma.spec ++++++
--- /var/tmp/diff_new_pack.kZDXe0/_old  2018-07-18 22:55:43.930604286 +0200
+++ /var/tmp/diff_new_pack.kZDXe0/_new  2018-07-18 22:55:43.934604273 +0200
@@ -24,7 +24,7 @@
 #
 
 Name:           rubygem-puma
-Version:        3.11.2
+Version:        3.12.0
 Release:        0
 %define mod_name puma
 %define mod_full_name %{mod_name}-%{version}
@@ -32,7 +32,7 @@
 BuildRequires:  openssl-devel
 # /MANUAL
 BuildRoot:      %{_tmppath}/%{name}-%{version}-build
-BuildRequires:  %{rubydevel >= 1.9.3}
+BuildRequires:  %{rubydevel >= 2.2}
 BuildRequires:  %{rubygem gem2rpm}
 BuildRequires:  ruby-macros >= 5
 BuildRequires:  update-alternatives

++++++ puma-3.11.2.gem -> puma-3.12.0.gem ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/History.md new/History.md
--- old/History.md      2018-01-19 20:23:10.000000000 +0100
+++ new/History.md      2018-07-13 18:08:52.000000000 +0200
@@ -1,3 +1,35 @@
+## 3.12.0 / 2018-07-13
+
+* 5 features:
+  * You can now specify which SSL ciphers the server should support, default 
is unchanged (#1478)
+  * The setting for Puma's `max_threads` is now in `Puma.stats` (#1604)
+  * Pool capacity is now in `Puma.stats` (#1579)
+  * Installs restricted to Ruby 2.2+ (#1506)
+  * `--control` is now deprecated in favor of `--control-url` (#1487)
+
+* 2 bugfixes:
+  * Workers will no longer accept more web requests than they have capacity to 
process. This prevents an issue where one worker would accept lots of requests 
while starving other workers (#1563)
+  * In a test env puma now emits the stack on an exception (#1557)
+
+## 3.11.4 / 2018-04-12
+
+* 2 features:
+  * Manage puma as a service using rc.d (#1529)
+  * Server stats are now available from a top level method (#1532)
+* 5 bugfixes:
+  * Fix parsing CLI options (#1482)
+  * Order of stderr and stdout is made before redirecting to a log file (#1511)
+  * Init.d fix of `ps -p` to check if pid exists (#1545)
+  * Early hints bugfix (#1550)
+  * Purge interrupt queue when closing socket fails (#1553)
+
+## 3.11.3 / 2018-03-05
+
+* 3 bugfixes:
+  * Add closed? to MiniSSL::Socket for use in reactor (#1510)
+  * Handle EOFError at the toplevel of the server threads (#1524) (#1507)
+  * Deal with zero sized bodies when using SSL (#1483)
+
 ## 3.11.2 / 2018-01-19
 
 * 1 bugfix:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/README.md new/README.md
--- old/README.md       2018-01-19 20:23:10.000000000 +0100
+++ new/README.md       2018-07-13 18:08:52.000000000 +0200
@@ -157,17 +157,27 @@
 ```
 
 Need a bit of security? Use SSL sockets:
-
 ```
 $ puma -b 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert'
 ```
+#### Controlling SSL Cipher Suites
+Need to use or avoid specific SSL cipher suites? Use ssl_cipher_filter or 
ssl_cipher_list options.
+#####Ruby:
+```
+$ puma -b 
'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert&ssl_cipher_filter=!aNULL:AES+SHA'
+```
+#####JRuby:
+```
+$ puma -b 
'ssl://127.0.0.1:9292?keystore=path_to_keystore&keystore-pass=keystore_password&ssl_cipher_list=TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA'
+```
+See https://www.openssl.org/docs/man1.0.2/apps/ciphers.html for cipher filter 
format and full list of cipher suites.
 
 ### Control/Status Server
 
 Puma has a built-in status/control app that can be used to query and control 
Puma itself.
 
 ```
-$ puma --control tcp://127.0.0.1:9293 --control-token foo
+$ puma --control-url tcp://127.0.0.1:9293 --control-token foo
 ```
 
 Puma will start the control server on localhost port 9293. All requests to the 
control server will need to include `token=foo` as a query parameter. This 
allows for simple authentication. Check out 
[status.rb](https://github.com/puma/puma/blob/master/lib/puma/app/status.rb) to 
see what the app has available.
@@ -175,7 +185,7 @@
 You can also interact with the control server via `pumactl`. This command will 
restart Puma:
 
 ```
-$ pumactl -C 'tcp://127.0.0.1:9293' --control-token foo restart
+$ pumactl --control-url 'tcp://127.0.0.1:9293' --control-token foo restart
 ```
 
 To see a list of `pumactl` options, use `pumactl --help`.
@@ -217,10 +227,10 @@
 
 ## Known Bugs
 
-For MRI versions 2.2.7, 2.2.8, 2.3.4 and 2.4.1, you may see ```stream closed 
in another thread (IOError)```. It may be caused by a [Ruby 
bug](https://bugs.ruby-lang.org/issues/13632). It can be fixed with the gem 
https://rubygems.org/gems/stopgap_13632:
+For MRI versions 2.2.7, 2.2.8, 2.2.9, 2.2.10 2.3.4 and 2.4.1, you may see 
```stream closed in another thread (IOError)```. It may be caused by a [Ruby 
bug](https://bugs.ruby-lang.org/issues/13632). It can be fixed with the gem 
https://rubygems.org/gems/stopgap_13632:
 
 ```ruby
-if %w(2.2.7 2.2.8 2.3.4 2.4.1).include? RUBY_VERSION
+if %w(2.2.7 2.2.8 2.2.9 2.2.10 2.3.4 2.4.1).include? RUBY_VERSION
   begin
     require 'stopgap_13632'
   rescue LoadError
Binary files old/checksums.yaml.gz and new/checksums.yaml.gz differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/docs/architecture.md new/docs/architecture.md
--- old/docs/architecture.md    2018-01-19 20:23:10.000000000 +0100
+++ new/docs/architecture.md    2018-07-13 18:08:52.000000000 +0200
@@ -33,4 +33,4 @@
 The `queue_requests` option is `true` by default, enabling the separate thread 
used to buffer requests as described above.
 
 If set to `false`, this buffer will not be used for connections while waiting 
for the request to arrive.
-In this mode, when a connection is accepted, it is added to the "todo" queue 
immediately, and a worker will syncronously do any waiting necessarry to read 
the HTTP request from the socket.
\ No newline at end of file
+In this mode, when a connection is accepted, it is added to the "todo" queue 
immediately, and a worker will synchronously do any waiting necessary to read 
the HTTP request from the socket.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/docs/restart.md new/docs/restart.md
--- old/docs/restart.md 2018-01-19 20:23:10.000000000 +0100
+++ new/docs/restart.md 2018-07-13 18:08:52.000000000 +0200
@@ -20,7 +20,7 @@
 
 But again beware, upgrading an application sometimes involves upgrading the 
database schema. With phased restart, there may be a moment during the 
deployment where processes belonging to the previous version and processes 
belonging to the new version both exist at the same time. Any database schema 
upgrades you perform must therefore be backwards-compatible with the old 
application version.
 
-If you perform a lot of database migrations, you probably should not use 
phased restart and use a normal/hot restart instead (pumactl restart). That 
way, no code is shared while deploying (in that case, preload_app might help 
for quicker deployment, see below).
+If you perform a lot of database migrations, you probably should not use 
phased restart and use a normal/hot restart instead (`pumactl restart`). That 
way, no code is shared while deploying (in that case, `preload_app!` might help 
for quicker deployment, see ["Clustered Mode" in the 
README](../README.md#clustered-mode)).
 
 ### Release Directory
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/docs/systemd.md new/docs/systemd.md
--- old/docs/systemd.md 2018-01-19 20:23:10.000000000 +0100
+++ new/docs/systemd.md 2018-07-13 18:08:52.000000000 +0200
@@ -102,6 +102,16 @@
 Note that the above configurations will work with Puma in either
 single process or cluster mode.
 
+### Sockets and symlinks
+
+When using releases folders, you should set the socket path using the
+shared folder path (ex. `/srv/projet/shared/tmp/puma.sock`), not the
+release folder path (`/srv/projet/releases/1234/tmp/puma.sock`).
+
+Puma will detect the release path socket as different than the one provided by
+systemd and attempt to bind it again, resulting in the exception
+ `There is already a server bound to:`.
+
 ## Usage
 
 Without socket activation, use `systemctl` as root (e.g. via `sudo`) as
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ext/puma_http11/mini_ssl.c 
new/ext/puma_http11/mini_ssl.c
--- old/ext/puma_http11/mini_ssl.c      2018-01-19 20:23:10.000000000 +0100
+++ new/ext/puma_http11/mini_ssl.c      2018-07-13 18:08:52.000000000 +0200
@@ -161,6 +161,9 @@
   ID sym_verify_mode = rb_intern("verify_mode");
   VALUE verify_mode = rb_funcall(mini_ssl_ctx, sym_verify_mode, 0);
 
+  ID sym_ssl_cipher_filter = rb_intern("ssl_cipher_filter");
+  VALUE ssl_cipher_filter = rb_funcall(mini_ssl_ctx, sym_ssl_cipher_filter, 0);
+
   ctx = SSL_CTX_new(SSLv23_server_method());
   conn->ctx = ctx;
 
@@ -175,7 +178,13 @@
   SSL_CTX_set_options(ctx, SSL_OP_CIPHER_SERVER_PREFERENCE | SSL_OP_NO_SSLv2 | 
SSL_OP_NO_SSLv3 | SSL_OP_SINGLE_DH_USE | SSL_OP_SINGLE_ECDH_USE | 
SSL_OP_NO_COMPRESSION);
   SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
 
-  SSL_CTX_set_cipher_list(ctx, "HIGH:!aNULL@STRENGTH");
+  if (!NIL_P(ssl_cipher_filter)) {
+    StringValue(ssl_cipher_filter);
+    SSL_CTX_set_cipher_list(ctx, RSTRING_PTR(ssl_cipher_filter));
+  }
+  else {
+    SSL_CTX_set_cipher_list(ctx, "HIGH:!aNULL@STRENGTH");
+  }
 
   DH *dh = get_dh1024();
   SSL_CTX_set_tmp_dh(ctx, dh);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ext/puma_http11/org/jruby/puma/MiniSSL.java 
new/ext/puma_http11/org/jruby/puma/MiniSSL.java
--- old/ext/puma_http11/org/jruby/puma/MiniSSL.java     2018-01-19 
20:23:10.000000000 +0100
+++ new/ext/puma_http11/org/jruby/puma/MiniSSL.java     2018-07-13 
18:08:52.000000000 +0200
@@ -170,6 +170,12 @@
         engine.setNeedClientAuth(true);
     }
 
+    IRubyObject sslCipherListObject = miniSSLContext.callMethod(threadContext, 
"ssl_cipher_list");
+    if (!sslCipherListObject.isNil()) {
+      String[] sslCipherList = 
sslCipherListObject.convertToString().asJavaString().split(",");
+      engine.setEnabledCipherSuites(sslCipherList);
+    }
+
     SSLSession session = engine.getSession();
     inboundNetData = new MiniSSLBuffer(session.getPacketBufferSize());
     outboundAppData = new MiniSSLBuffer(session.getApplicationBufferSize());
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/puma/binder.rb new/lib/puma/binder.rb
--- old/lib/puma/binder.rb      2018-01-19 20:23:10.000000000 +0100
+++ new/lib/puma/binder.rb      2018-07-13 18:08:52.000000000 +0200
@@ -162,6 +162,7 @@
             end
 
             ctx.keystore_pass = params['keystore-pass']
+            ctx.ssl_cipher_list = params['ssl_cipher_list'] if 
params['ssl_cipher_list']
           else
             unless params['key']
               @events.error "Please specify the SSL key via 'key='"
@@ -182,6 +183,7 @@
             end
 
             ctx.ca = params['ca'] if params['ca']
+            ctx.ssl_cipher_filter = params['ssl_cipher_filter'] if 
params['ssl_cipher_filter']
           end
 
           if params['verify_mode']
@@ -313,6 +315,7 @@
       s.setsockopt(Socket::SOL_SOCKET,Socket::SO_REUSEADDR, true)
       s.listen backlog
 
+
       ssl = MiniSSL::Server.new s, ctx
       env = @proto_env.dup
       env[HTTPS_KEY] = HTTPS
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/puma/cli.rb new/lib/puma/cli.rb
--- old/lib/puma/cli.rb 2018-01-19 20:23:10.000000000 +0100
+++ new/lib/puma/cli.rb 2018-07-13 18:08:52.000000000 +0200
@@ -1,6 +1,7 @@
 require 'optparse'
 require 'uri'
 
+require 'puma'
 require 'puma/configuration'
 require 'puma/launcher'
 require 'puma/const'
@@ -83,6 +84,14 @@
       raise UnsupportedOption
     end
 
+    def configure_control_url(command_line_arg)
+      if command_line_arg
+        @control_url = command_line_arg
+      elsif Puma.jruby?
+        unsupported "No default url available on JRuby"
+      end
+    end
+
     # Build the OptionParser object to handle the available options.
     #
 
@@ -97,13 +106,13 @@
             file_config.load arg
           end
 
-          o.on "--control URL", "The bind url to use for the control server",
-            "Use 'auto' to use temp unix server" do |arg|
-            if arg
-              @control_url = arg
-            elsif Puma.jruby?
-              unsupported "No default url available on JRuby"
-            end
+          o.on "--control-url URL", "The bind url to use for the control 
server. Use 'auto' to use temp unix server" do |arg|
+            configure_control_url(arg)
+          end
+
+          # alias --control-url for backwards-compatibility
+          o.on "--control URL", "DEPRECATED alias for --control-url" do |arg|
+            configure_control_url(arg)
           end
 
           o.on "--control-token TOKEN",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/puma/client.rb new/lib/puma/client.rb
--- old/lib/puma/client.rb      2018-01-19 20:23:10.000000000 +0100
+++ new/lib/puma/client.rb      2018-07-13 18:08:52.000000000 +0200
@@ -21,6 +21,17 @@
 
   class ConnectionError < RuntimeError; end
 
+  # An instance of this class represents a unique request from a client.
+  # For example a web request from a browser or from CURL. This
+  #
+  # An instance of `Puma::Client` can be used as if it were an IO object
+  # for example it is passed into `IO.select` inside of the `Puma::Reactor`.
+  # This is accomplished by the `to_io` method which gets called on any
+  # non-IO objects being used with the IO api such as `IO.select.
+  #
+  # Instances of this class are responsible for knowing if
+  # the header and body are fully buffered via the `try_to_finish` method.
+  # They can be used to "time out" a response via the `timeout_at` reader.
   class Client
     include Puma::Const
     extend  Puma::Delegation
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/puma/cluster.rb new/lib/puma/cluster.rb
--- old/lib/puma/cluster.rb     2018-01-19 20:23:10.000000000 +0100
+++ new/lib/puma/cluster.rb     2018-07-13 18:08:52.000000000 +0200
@@ -5,6 +5,17 @@
 require 'time'
 
 module Puma
+  # This class is instantiated by the `Puma::Launcher` and used
+  # to boot and serve a Ruby application when puma "workers" are needed
+  # i.e. when using multi-processes. For example `$ puma -w 5`
+  #
+  # At the core of this class is running an instance of `Puma::Server` which
+  # gets created via the `start_server` method from the `Puma::Runner` class
+  # that this inherits from.
+  #
+  # An instance of this class will spawn the number of processes passed in
+  # via the `spawn_workers` method call. Each worker will have it's own
+  # instance of a `Puma::Server`.
   class Cluster < Runner
     WORKER_CHECK_INTERVAL = 5
 
@@ -281,7 +292,9 @@
           begin
             b = server.backlog || 0
             r = server.running || 0
-            payload = %Q!#{base_payload}{ "backlog":#{b}, "running":#{r} }\n!
+            t = server.pool_capacity || 0
+            m = server.max_threads || 0
+            payload = %Q!#{base_payload}{ "backlog":#{b}, "running":#{r}, 
"pool_capacity":#{t}, "max_threads": #{m} }\n!
             io << payload
           rescue IOError
             Thread.current.purge_interrupt_queue if Thread.current.respond_to? 
:purge_interrupt_queue
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/puma/const.rb new/lib/puma/const.rb
--- old/lib/puma/const.rb       2018-01-19 20:23:10.000000000 +0100
+++ new/lib/puma/const.rb       2018-07-13 18:08:52.000000000 +0200
@@ -98,8 +98,8 @@
   # too taxing on performance.
   module Const
 
-    PUMA_VERSION = VERSION = "3.11.2".freeze
-    CODE_NAME = "Love Song".freeze
+    PUMA_VERSION = VERSION = "3.12.0".freeze
+    CODE_NAME = "Llamas in Pajamas".freeze
     PUMA_SERVER_STRING = ['puma', PUMA_VERSION, CODE_NAME].join(' ').freeze
 
     FAST_TRACK_KA_TIMEOUT = 0.2
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/puma/control_cli.rb new/lib/puma/control_cli.rb
--- old/lib/puma/control_cli.rb 2018-01-19 20:23:10.000000000 +0100
+++ new/lib/puma/control_cli.rb 2018-07-13 18:08:52.000000000 +0200
@@ -69,6 +69,7 @@
       end
 
       opts.order!(argv) { |a| opts.terminate a }
+      opts.parse!
 
       @command = argv.shift
 
@@ -204,7 +205,6 @@
           Process.kill "SIGUSR1", @pid
 
         else
-          message "Puma is started"
           return
         end
 
@@ -220,7 +220,7 @@
     end
 
     def run
-      start if @command == "start"
+      return start if @command == "start"
 
       prepare_configuration
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/puma/dsl.rb new/lib/puma/dsl.rb
--- old/lib/puma/dsl.rb 2018-01-19 20:23:10.000000000 +0100
+++ new/lib/puma/dsl.rb 2018-07-13 18:08:52.000000000 +0200
@@ -146,13 +146,13 @@
     # them
     #
     def persistent_timeout(seconds)
-      @options[:persistent_timeout] = seconds
+      @options[:persistent_timeout] = Integer(seconds)
     end
 
     # Define how long the tcp socket stays open, if no data has been received
     #
     def first_data_timeout(seconds)
-      @options[:first_data_timeout] = seconds
+      @options[:first_data_timeout] = Integer(seconds)
     end
 
     # Work around leaky apps that leave garbage in Thread locals
@@ -169,7 +169,7 @@
     end
 
     # When shutting down, drain the accept socket of pending
-    # connections and proces them. This loops over the accept
+    # connections and process them. This loops over the accept
     # socket until there are no more read events and then stops
     # looking and waits for the requests to finish.
     def drain_on_shutdown(which=true)
@@ -424,17 +424,17 @@
     # that have not checked in within the given +timeout+.
     # This mitigates hung processes. Default value is 60 seconds.
     def worker_timeout(timeout)
-      @options[:worker_timeout] = timeout
+      @options[:worker_timeout] = Integer(timeout)
     end
 
     # *Cluster mode only* Set the timeout for workers to boot
     def worker_boot_timeout(timeout)
-      @options[:worker_boot_timeout] = timeout
+      @options[:worker_boot_timeout] = Integer(timeout)
     end
 
     # *Cluster mode only* Set the timeout for worker shutdown
     def worker_shutdown_timeout(timeout)
-      @options[:worker_shutdown_timeout] = timeout
+      @options[:worker_shutdown_timeout] = Integer(timeout)
     end
 
     # When set to true (the default), workers accept all requests
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/puma/launcher.rb new/lib/puma/launcher.rb
--- old/lib/puma/launcher.rb    2018-01-19 20:23:10.000000000 +0100
+++ new/lib/puma/launcher.rb    2018-07-13 18:08:52.000000000 +0200
@@ -86,6 +86,7 @@
       else
         @runner = Single.new(self, @events)
       end
+      Puma.stats_object = @runner
 
       @status = :run
     end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/puma/minissl.rb new/lib/puma/minissl.rb
--- old/lib/puma/minissl.rb     2018-01-19 20:23:10.000000000 +0100
+++ new/lib/puma/minissl.rb     2018-07-13 18:08:52.000000000 +0200
@@ -16,6 +16,10 @@
         @socket
       end
 
+      def closed?
+        @socket.closed?
+      end
+
       def readpartial(size)
         while true
           output = @engine.read
@@ -77,6 +81,8 @@
       end
 
       def write(data)
+        return 0 if data.empty?
+
         need = data.bytesize
 
         while true
@@ -118,7 +124,7 @@
 
       def read_and_drop(timeout = 1)
         return :timeout unless IO.select([@socket], nil, nil, timeout)
-        read_nonblock(1024)
+        return :eof unless read_nonblock(1024)
         :drop
       rescue Errno::EAGAIN
         # do nothing
@@ -135,7 +141,7 @@
           # Don't let this socket hold this loop forever.
           # If it can't send more packets within 1s, then give up.
           while should_drop_bytes?
-            return if read_and_drop(1) == :timeout
+            return if [:timeout, :eof].include?(read_and_drop(1))
           end
         rescue IOError, SystemCallError
           Thread.current.purge_interrupt_queue if Thread.current.respond_to? 
:purge_interrupt_queue
@@ -174,6 +180,7 @@
         # jruby-specific Context properties: java uses a keystore and password 
pair rather than a cert/key pair
         attr_reader :keystore
         attr_accessor :keystore_pass
+        attr_accessor :ssl_cipher_list
 
         def keystore=(keystore)
           raise ArgumentError, "No such keystore file '#{keystore}'" unless 
File.exist? keystore
@@ -189,6 +196,7 @@
         attr_reader :key
         attr_reader :cert
         attr_reader :ca
+        attr_accessor :ssl_cipher_filter
 
         def key=(key)
           raise ArgumentError, "No such key file '#{key}'" unless File.exist? 
key
@@ -243,7 +251,7 @@
       end
 
       def close
-        @socket.close
+        @socket.close unless @socket.closed?       # closed? call is for 
Windows
       end
     end
   end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/puma/reactor.rb new/lib/puma/reactor.rb
--- old/lib/puma/reactor.rb     2018-01-19 20:23:10.000000000 +0100
+++ new/lib/puma/reactor.rb     2018-07-13 18:08:52.000000000 +0200
@@ -2,15 +2,54 @@
 require 'puma/minissl'
 
 module Puma
+  # Internal Docs, Not a public interface.
+  #
+  # The Reactor object is responsible for ensuring that a request has been
+  # completely received before it starts to be processed. This may be known as 
read buffering.
+  # If read buffering is not done, and no other read buffering is performed 
(such as by an application server
+  # such as nginx) then the application would be subject to a slow client 
attack.
+  #
+  # Each Puma "worker" process has its own Reactor. For example if you start 
puma with `$ puma -w 5` then
+  # it will have 5 workers and each worker will have it's own reactor.
+  #
+  # For a graphical representation of how the reactor works see 
[architecture.md](https://github.com/puma/puma/blob/master/docs/architecture.md#connection-pipeline).
+  #
+  # ## Reactor Flow
+  #
+  # A request comes into a `Puma::Server` instance, it is then passed to a 
`Puma::Reactor` instance.
+  # The reactor stores the request in an array and calls `IO.select` on the 
array in a loop.
+  #
+  # When the request is written to by the client then the `IO.select` will 
"wake up" and
+  # return the references to any objects that caused it to "wake". The reactor
+  # then loops through each of these request objects, and sees if they're  
complete. If they
+  # have a full header and body then the reactor passes the request to a 
thread pool.
+  # Once in a thread pool, a "worker thread" can run the the application's 
Ruby code against the request.
+  #
+  # If the request is not complete, then it stays in the array, and the next 
time any
+  # data is written to that socket reference, then the loop is woken up and it 
is checked for completeness again.
+  #
+  # A detailed example is given in the docs for `run_internal` which is where 
the bulk
+  # of this logic lives.
   class Reactor
     DefaultSleepFor = 5
 
+    # Creates an instance of Puma::Reactor
+    #
+    # The `server` argument is an instance of `Puma::Server`
+    # this is used to write a response for "low level errors"
+    # when there is an exception inside of the reactor.
+    #
+    # The `app_pool` is an instance of `Puma::ThreadPool`.
+    # Once a request is fully formed (header and body are received)
+    # it will be passed to the `app_pool`.
     def initialize(server, app_pool)
       @server = server
       @events = server.events
       @app_pool = app_pool
 
       @mutex = Mutex.new
+
+      # Read / Write pipes to wake up internal while loop
       @ready, @trigger = Puma::Util.pipe
       @input = []
       @sleep_for = DefaultSleepFor
@@ -21,6 +60,64 @@
 
     private
 
+
+    # Until a request is added via the `add` method this method will internally
+    # loop, waiting on the `sockets` array objects. The only object in this
+    # array at first is the `@ready` IO object, which is the read end of a pipe
+    # connected to `@trigger` object. When `@trigger` is written to, then the 
loop
+    # will break on `IO.select` and return an array.
+    #
+    # ## When a request is added:
+    #
+    # When the `add` method is called, an instance of `Puma::Client` is added 
to the `@input` array.
+    # Next the `@ready` pipe is "woken" by writing a string of `"*"` to 
`@trigger`.
+    #
+    # When that happens, the internal loop stops blocking at `IO.select` and 
returns a reference
+    # to whatever "woke" it up. On the very first loop, the only thing in 
`sockets` is `@ready`.
+    # When `@trigger` is written-to, the loop "wakes" and the `ready`
+    # variable returns an array of arrays that looks like `[[#<IO:fd 10>], [], 
[]]` where the
+    # first IO object is the `@ready` object. This first array `[#<IO:fd 10>]`
+    # is saved as a `reads` variable.
+    #
+    # The `reads` variable is iterated through. In the case that the object
+    # is the same as the `@ready` input pipe, then we know that there was a 
`trigger` event.
+    #
+    # If there was a trigger event, then one byte of `@ready` is read into 
memory. In the case of the first request,
+    # the reactor sees that it's a `"*"` value and the reactor adds the 
contents of `@input` into the `sockets` array.
+    # The while then loop continues to iterate again, but now the `sockets` 
array contains a `Puma::Client` instance in addition
+    # to the `@ready` IO object. For example: `[#<IO:fd 10>, 
#<Puma::Client:0x3fdc1103bee8 @ready=false>]`.
+    #
+    # Since the `Puma::Client` in this example has data that has not been read 
yet,
+    # the `IO.select` is immediately able to "wake" and read from the 
`Puma::Client`. At this point the
+    # `ready` output looks like this: `[[#<Puma::Client:0x3fdc1103bee8 
@ready=false>], [], []]`.
+    #
+    # Each element in the first entry is iterated over. The `Puma::Client` 
object is not
+    # the `@ready` pipe, so the reactor checks to see if it has the fully 
header and body with
+    # the `Puma::Client#try_to_finish` method. If the full request has been 
sent,
+    # then the request is passed off to the `@app_pool` thread pool so that a 
"worker thread"
+    # can pick up the request and begin to execute application logic. This is 
done
+    # via `@app_pool << c`. The `Puma::Client` is then removed from the 
`sockets` array.
+    #
+    # If the request body is not present then nothing will happen, and the 
loop will iterate
+    # again. When the client sends more data to the socket the `Puma::Client` 
object will
+    # wake up the `IO.select` and it can again be checked to see if it's ready 
to be
+    # passed to the thread pool.
+    #
+    # ## Time Out Case
+    #
+    # In addition to being woken via a write to one of the sockets the 
`IO.select` will
+    # periodically "time out" of the sleep. One of the functions of this is to 
check for
+    # any requests that have "timed out". At the end of the loop it's checked 
to see if
+    # the first element in the `@timeout` array has exceed it's allowed time. 
If so,
+    # the client object is removed from the timeout aray, a 408 response is 
written.
+    # Then it's connection is closed, and the object is removed from the 
`sockets` array
+    # that watches for new data.
+    #
+    # This behavior loops until all the objects that have timed out have been 
removed.
+    #
+    # Once all the timeouts have been processed, the next duration of the 
`IO.select` sleep
+    # will be set to be equal to the amount of time it will take for the next 
timeout to occur.
+    # This calculation happens in `calculate_sleep`.
     def run_internal
       sockets = @sockets
 
@@ -163,6 +260,16 @@
       end
     end
 
+    # The `calculate_sleep` sets the value that the `IO.select` will
+    # sleep for in the main reactor loop when no sockets are being written to.
+    #
+    # The values kept in `@timeouts` are sorted so that the first timeout
+    # comes first in the array. When there are no timeouts the default timeout 
is used.
+    #
+    # Otherwise a sleep value is set that is the same as the amount of time it
+    # would take for the first element to time out.
+    #
+    # If that value is in the past, then a sleep value of zero is used.
     def calculate_sleep
       if @timeouts.empty?
         @sleep_for = DefaultSleepFor
@@ -177,6 +284,31 @@
       end
     end
 
+    # This method adds a connection to the reactor
+    #
+    # Typically called by `Puma::Server` the value passed in
+    # is usually a `Puma::Client` object that responds like an IO
+    # object.
+    #
+    # The main body of the reactor loop is in `run_internal` and it
+    # will sleep on `IO.select`. When a new connection is added to the
+    # reactor it cannot be added directly to the `sockets` aray, because
+    # the `IO.select` will not be watching for it yet.
+    #
+    # Instead what needs to happen is that `IO.select` needs to be woken up,
+    # the contents of `@input` added to the `sockets` array, and then
+    # another call to `IO.select` needs to happen. Since the `Puma::Client`
+    # object can be read immediately, it does not block, but instead returns
+    # right away.
+    #
+    # This behavior is accomplished by writing to `@trigger` which wakes up
+    # the `IO.select` and then there is logic to detect the value of `*`,
+    # pull the contents from `@input` and add them to the sockets array.
+    #
+    # If the object passed in has a timeout value in `timeout_at` then
+    # it is added to a `@timeouts` array. This array is then re-arranged
+    # so that the first element to timeout will be at the front of the
+    # array. Then a value to sleep for is derived in the call to 
`calculate_sleep`
     def add(c)
       @mutex.synchronize do
         @input << c
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/puma/runner.rb new/lib/puma/runner.rb
--- old/lib/puma/runner.rb      2018-01-19 20:23:10.000000000 +0100
+++ new/lib/puma/runner.rb      2018-07-13 18:08:52.000000000 +0200
@@ -2,6 +2,9 @@
 require 'puma/const'
 
 module Puma
+  # Generic class that is used by `Puma::Cluster` and `Puma::Single` to
+  # serve requests. This class spawns a new instance of `Puma::Server` via
+  # a call to `start_server`.
   class Runner
     def initialize(cli, events)
       @launcher = cli
@@ -19,6 +22,10 @@
       @options[:environment] == "development"
     end
 
+    def test?
+      @options[:environment] == "test"
+    end
+
     def log(str)
       @events.log str
     end
@@ -165,7 +172,7 @@
         server.early_hints = true
       end
 
-      unless development?
+      unless development? || test?
         server.leak_stack_on_error = false
       end
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/puma/server.rb new/lib/puma/server.rb
--- old/lib/puma/server.rb      2018-01-19 20:23:10.000000000 +0100
+++ new/lib/puma/server.rb      2018-07-13 18:08:52.000000000 +0200
@@ -23,6 +23,15 @@
 module Puma
 
   # The HTTP Server itself. Serves out a single Rack app.
+  #
+  # This class is used by the `Puma::Single` and `Puma::Cluster` classes
+  # to generate one or more `Puma::Server` instances capable of handling 
requests.
+  # Each Puma process will contain one `Puma::Server` instacne.
+  #
+  # The `Puma::Server` instance pulls requests from the socket, adds them to a
+  # `Puma::Reactor` where they get eventually passed to a `Puma::ThreadPool`.
+  #
+  # Each `Puma::Server` will have one reactor and one thread pool.
   class Server
 
     include Puma::Const
@@ -159,6 +168,18 @@
       @thread_pool and @thread_pool.spawned
     end
 
+
+    # This number represents the number of requests that
+    # the server is capable of taking right now.
+    #
+    # For example if the number is 5 then it means
+    # there are 5 threads sitting idle ready to take
+    # a request. If one request comes in, then the
+    # value would be 4 until it finishes processing.
+    def pool_capacity
+      @thread_pool and @thread_pool.pool_capacity
+    end
+
     # Lopez Mode == raw tcp apps
 
     def run_lopez_mode(background=true)
@@ -220,7 +241,11 @@
                   # nothing
                 rescue Errno::ECONNABORTED
                   # client closed the socket even before accept
-                  io.close rescue nil
+                  begin
+                    io.close
+                  rescue
+                    Thread.current.purge_interrupt_queue if 
Thread.current.respond_to? :purge_interrupt_queue
+                  end
                 end
               end
             end
@@ -237,7 +262,12 @@
         STDERR.puts "Exception handling servers: #{e.message} (#{e.class})"
         STDERR.puts e.backtrace
       ensure
-        @check.close
+        begin
+          @check.close
+        rescue
+          Thread.current.purge_interrupt_queue if Thread.current.respond_to? 
:purge_interrupt_queue
+        end
+
         @notify.close
 
         if @status != :restart and @own_binder
@@ -295,7 +325,7 @@
           client.close
 
           @events.parse_error self, client.env, e
-        rescue ConnectionError
+        rescue ConnectionError, EOFError
           client.close
         else
           if process_now
@@ -372,7 +402,11 @@
                   # nothing
                 rescue Errno::ECONNABORTED
                   # client closed the socket even before accept
-                  io.close rescue nil
+                  begin
+                    io.close
+                  rescue
+                    Thread.current.purge_interrupt_queue if 
Thread.current.respond_to? :purge_interrupt_queue
+                  end
                 end
               end
             end
@@ -606,7 +640,7 @@
                 fast_write client, "#{k}: #{v}\r\n"
               end
             else
-              fast_write client, "#{k}: #{v}\r\n"
+              fast_write client, "#{k}: #{vs}\r\n"
             end
           end
 
@@ -755,8 +789,8 @@
 
         begin
           res_body.each do |part|
+            next if part.bytesize.zero?
             if chunked
-              next if part.bytesize.zero?
               fast_write client, part.bytesize.to_s(16)
               fast_write client, line_ending
               fast_write client, part
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/puma/single.rb new/lib/puma/single.rb
--- old/lib/puma/single.rb      2018-01-19 20:23:10.000000000 +0100
+++ new/lib/puma/single.rb      2018-07-13 18:08:52.000000000 +0200
@@ -3,11 +3,20 @@
 require 'puma/plugin'
 
 module Puma
+  # This class is instantiated by the `Puma::Launcher` and used
+  # to boot and serve a Ruby application when no puma "workers" are needed
+  # i.e. only using "threaded" mode. For example `$ puma -t 1:5`
+  #
+  # At the core of this class is running an instance of `Puma::Server` which
+  # gets created via the `start_server` method from the `Puma::Runner` class
+  # that this inherits from.
   class Single < Runner
     def stats
       b = @server.backlog || 0
       r = @server.running || 0
-      %Q!{ "backlog": #{b}, "running": #{r} }!
+      t = @server.pool_capacity || 0
+      m = @server.max_threads || 0
+      %Q!{ "backlog": #{b}, "running": #{r}, "pool_capacity": #{t}, 
"max_threads": #{m} }!
     end
 
     def restart
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/puma/thread_pool.rb new/lib/puma/thread_pool.rb
--- old/lib/puma/thread_pool.rb 2018-01-19 20:23:10.000000000 +0100
+++ new/lib/puma/thread_pool.rb 2018-07-13 18:08:52.000000000 +0200
@@ -1,8 +1,17 @@
 require 'thread'
 
 module Puma
-  # A simple thread pool management object.
+  # Internal Docs for A simple thread pool management object.
   #
+  # Each Puma "worker" has a thread pool to process requests.
+  #
+  # First a connection to a client is made in `Puma::Server`. It is wrapped in 
a
+  # `Puma::Client` instance and then passed to the `Puma::Reactor` to ensure
+  # the whole request is buffered into memory. Once the request is ready, it 
is passed into
+  # a thread pool via the `Puma::ThreadPool#<<` operator where it is stored in 
a `@todo` array.
+  #
+  # Each thread in the pool has an internal loop where it pulls a request from 
the `@todo` array
+  # and proceses it.
   class ThreadPool
     class ForceShutdown < RuntimeError
     end
@@ -49,7 +58,7 @@
       @clean_thread_locals = false
     end
 
-    attr_reader :spawned, :trim_requested
+    attr_reader :spawned, :trim_requested, :waiting
     attr_accessor :clean_thread_locals
 
     def self.clean_thread_locals
@@ -64,6 +73,10 @@
       @mutex.synchronize { @todo.size }
     end
 
+    def pool_capacity
+      waiting + (@max - spawned)
+    end
+
     # :nodoc:
     #
     # Must be called with @mutex held!
@@ -153,16 +166,42 @@
       end
     end
 
+    # This method is used by `Puma::Server` to let the server know when
+    # the thread pool can pull more requests from the socket and
+    # pass to the reactor.
+    #
+    # The general idea is that the thread pool can only work on a fixed
+    # number of requests at the same time. If it is already processing that
+    # number of requests then it is at capacity. If another Puma process has
+    # spare capacity, then the request can be left on the socket so the other
+    # worker can pick it up and process it.
+    #
+    # For example: if there are 5 threads, but only 4 working on
+    # requests, this method will not wait and the `Puma::Server`
+    # can pull a request right away.
+    #
+    # If there are 5 threads and all 5 of them are busy, then it will
+    # pause here, and wait until the `not_full` condition variable is
+    # signaled, usually this indicates that a request has been processed.
+    #
+    # It's important to note that even though the server might accept another
+    # request, it might not be added to the `@todo` array right away.
+    # For example if a slow client has only sent a header, but not a body
+    # then the `@todo` array would stay the same size as the reactor works
+    # to try to buffer the request. In tha scenario the next call to this
+    # method would not block and another request would be added into the 
reactor
+    # by the server. This would continue until a fully bufferend request
+    # makes it through the reactor and can then be processed by the thread 
pool.
     def wait_until_not_full
       @mutex.synchronize do
         while true
           return if @shutdown
-          return if @waiting > 0
 
           # If we can still spin up new threads and there
-          # is work queued, then accept more work until we would
+          # is work queued that cannot be handled by waiting
+          # threads, then accept more work until we would
           # spin up the max number of threads.
-          return if @todo.size < @max - @spawned
+          return if @todo.size - @waiting < @max - @spawned
 
           @not_full.wait @mutex
         end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/puma.rb new/lib/puma.rb
--- old/lib/puma.rb     2018-01-19 20:23:10.000000000 +0100
+++ new/lib/puma.rb     2018-07-13 18:08:52.000000000 +0200
@@ -12,4 +12,12 @@
   autoload :Const, 'puma/const'
   autoload :Server, 'puma/server'
   autoload :Launcher, 'puma/launcher'
+
+  def self.stats_object=(val)
+    @get_stats = val
+  end
+
+  def self.stats
+    @get_stats.stats
+  end
 end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/rack/handler/puma.rb new/lib/rack/handler/puma.rb
--- old/lib/rack/handler/puma.rb        2018-01-19 20:23:10.000000000 +0100
+++ new/lib/rack/handler/puma.rb        2018-07-13 18:08:52.000000000 +0200
@@ -9,6 +9,7 @@
       }
 
       def self.config(app, options = {})
+        require 'puma'
         require 'puma/configuration'
         require 'puma/events'
         require 'puma/launcher'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/metadata new/metadata
--- old/metadata        2018-01-19 20:23:10.000000000 +0100
+++ new/metadata        2018-07-13 18:08:52.000000000 +0200
@@ -1,14 +1,14 @@
 --- !ruby/object:Gem::Specification
 name: puma
 version: !ruby/object:Gem::Version
-  version: 3.11.2
+  version: 3.12.0
 platform: ruby
 authors:
 - Evan Phoenix
 autorequire: 
 bindir: bin
 cert_chain: []
-date: 2018-01-19 00:00:00.000000000 Z
+date: 2018-07-13 00:00:00.000000000 Z
 dependencies: []
 description: Puma is a simple, fast, threaded, and highly concurrent HTTP 1.1 
server
   for Ruby/Rack applications. Puma is intended for use in both development and 
production
@@ -96,6 +96,9 @@
 - tools/jungle/init.d/README.md
 - tools/jungle/init.d/puma
 - tools/jungle/init.d/run-puma
+- tools/jungle/rc.d/README.md
+- tools/jungle/rc.d/puma
+- tools/jungle/rc.d/puma.conf
 - tools/jungle/upstart/README.md
 - tools/jungle/upstart/puma-manager.conf
 - tools/jungle/upstart/puma.conf
@@ -113,7 +116,7 @@
   requirements:
   - - ">="
     - !ruby/object:Gem::Version
-      version: 1.9.3
+      version: '2.2'
 required_rubygems_version: !ruby/object:Gem::Requirement
   requirements:
   - - ">="
@@ -121,7 +124,7 @@
       version: '0'
 requirements: []
 rubyforge_project: 
-rubygems_version: 2.6.8
+rubygems_version: 2.7.6
 signing_key: 
 specification_version: 4
 summary: Puma is a simple, fast, threaded, and highly concurrent HTTP 1.1 
server for
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tools/jungle/README.md new/tools/jungle/README.md
--- old/tools/jungle/README.md  2018-01-19 20:23:10.000000000 +0100
+++ new/tools/jungle/README.md  2018-07-13 18:08:52.000000000 +0200
@@ -1,9 +1,5 @@
 # Puma as a service
 
-## Init.d
-
-See `/tools/jungle/init.d` for tools to use with init.d and start-stop-daemon.
-
 ## Upstart
 
 See `/tools/jungle/upstart` for Ubuntu's upstart scripts.
@@ -11,3 +7,13 @@
 ## Systemd
 
 See [/docs/systemd](https://github.com/puma/puma/blob/master/docs/systemd.md).
+
+## Init.d
+
+Deprecatation Warning : `init.d` was replaced by `systemd` since Debian 8 and 
Ubuntu 16.04, you should look into 
[/docs/systemd](https://github.com/puma/puma/blob/master/docs/systemd.md) 
unless you are on an older OS.
+
+See `/tools/jungle/init.d` for tools to use with init.d and start-stop-daemon.
+
+## rc.d
+
+See `/tools/jungle/rc.d` for FreeBSD's rc.d scripts
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tools/jungle/init.d/README.md 
new/tools/jungle/init.d/README.md
--- old/tools/jungle/init.d/README.md   2018-01-19 20:23:10.000000000 +0100
+++ new/tools/jungle/init.d/README.md   2018-07-13 18:08:52.000000000 +0200
@@ -1,5 +1,7 @@
 # Puma daemon service
 
+Deprecatation Warning : `init.d` was replaced by `systemd` since Debian 8 and 
Ubuntu 16.04, you should look into 
[/docs/systemd](https://github.com/puma/puma/blob/master/docs/systemd.md) 
unless you are on an older OS. 
+
 Init script to manage multiple Puma servers on the same box using 
start-stop-daemon.
 
 ## Installation 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tools/jungle/init.d/puma new/tools/jungle/init.d/puma
--- old/tools/jungle/init.d/puma        2018-01-19 20:23:10.000000000 +0100
+++ new/tools/jungle/init.d/puma        2018-07-13 18:08:52.000000000 +0200
@@ -48,7 +48,7 @@
   if [ -e $PIDFILE ]; then
     PID=`cat $PIDFILE`
     # If the puma isn't running, run it, otherwise restart it.
-    if [ "`ps -A -o pid= | grep -c $PID`" -eq 0 ]; then
+    if ps -p $PID > /dev/null; then
       do_start_one_do $1
     else
       do_restart_one $1
@@ -105,7 +105,7 @@
   STATEFILE=$1/tmp/puma/state
   if [ -e $PIDFILE ]; then
     PID=`cat $PIDFILE`
-    if [ "`ps -A -o pid= | grep -c $PID`" -eq 0 ]; then
+    if ps -p $PID > /dev/null; then
       log_daemon_msg "---> Puma $1 isn't running."
     else
       log_daemon_msg "---> About to kill PID `cat $PIDFILE`"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tools/jungle/init.d/run-puma 
new/tools/jungle/init.d/run-puma
--- old/tools/jungle/init.d/run-puma    2018-01-19 20:23:10.000000000 +0100
+++ new/tools/jungle/init.d/run-puma    2018-07-13 18:08:52.000000000 +0200
@@ -15,4 +15,4 @@
 fi
 
 app=$1; config=$2; log=$3;
-cd $app && exec bundle exec puma -C $config 2>&1 >> $log
+cd $app && exec bundle exec puma -C $config >> $log 2>&1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tools/jungle/rc.d/README.md 
new/tools/jungle/rc.d/README.md
--- old/tools/jungle/rc.d/README.md     1970-01-01 01:00:00.000000000 +0100
+++ new/tools/jungle/rc.d/README.md     2018-07-13 18:08:52.000000000 +0200
@@ -0,0 +1,74 @@
+# Puma as a service using rc.d
+
+Manage multilpe Puma servers as services on one box using FreeBSD's rc.d 
service.
+
+## Dependencies
+
+* `jq` - a command-line json parser is needed to parse the json in the config 
file
+
+## Installation
+
+    # Copy the puma script to the rc.d directory (make sure everyone has 
read/execute perms)
+    sudo cp puma /usr/local/etc/rc.d/
+
+    # Create an empty configuration file
+    sudo touch /usr/local/etc/puma.conf
+
+    # Enable the puma service
+    sudo echo 'puma_enable="YES"' >> /etc/rc.conf
+
+## Managing the jungle
+
+Puma apps are referenced in /usr/local/etc/puma.conf by default.
+
+Start the jungle running:
+
+`service puma start`
+
+This script will run at boot time.
+
+
+You can also stop the jungle (stops ALL puma instances) by running:
+
+`service puma stop`
+
+
+To restart the jungle:
+
+`service puma restart`
+
+## Conventions
+
+* The script expects:
+  * a config file to exist under `config/puma.rb` in your app. E.g.: 
`/home/apps/my-app/config/puma.rb`.
+
+You can always change those defaults by editing the scripts.
+
+## Here's what a minimal app's config file should have
+
+```
+{
+       "servers" : [
+               {
+                       "dir": "/path/to/rails/project",
+                       "user": "deploy-user",
+                       "ruby_version": "ruby.version",
+                       "ruby_env": "rbenv"
+               }
+       ]
+}
+```
+
+## Before starting...
+
+You need to customise `puma.conf` to:
+
+* Set the right user your app should be running on unless you want root to 
execute it!
+* Set the directory of the app
+* Set the ruby version to execute
+* Set the ruby environment (currently set to rbenv, since that is the only 
ruby environment currently supported)
+* Add additional server instances following the scheme in the example
+
+## Notes:
+
+Only rbenv is currently supported.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tools/jungle/rc.d/puma new/tools/jungle/rc.d/puma
--- old/tools/jungle/rc.d/puma  1970-01-01 01:00:00.000000000 +0100
+++ new/tools/jungle/rc.d/puma  2018-07-13 18:08:52.000000000 +0200
@@ -0,0 +1,61 @@
+#!/bin/sh
+#
+
+# PROVIDE: puma
+
+. /etc/rc.subr
+
+name="puma"
+start_cmd="puma_start"
+stop_cmd="puma_stop"
+restart_cmd="puma_restart"
+rcvar=puma_enable
+required_files=/usr/local/etc/puma.conf
+
+puma_start()
+{
+       server_count=$(/usr/local/bin/jq ".servers[] .ruby_env" 
/usr/local/etc/puma.conf | wc -l)
+       i=0     
+       while [ "$i" -lt "$server_count" ]; do
+               rb_env=$(/usr/local/bin/jq -r ".servers[$i].ruby_env" 
/usr/local/etc/puma.conf)
+               dir=$(/usr/local/bin/jq -r ".servers[$i].dir" 
/usr/local/etc/puma.conf)
+               user=$(/usr/local/bin/jq -r ".servers[$i].user" 
/usr/local/etc/puma.conf)
+               rb_ver=$(/usr/local/bin/jq -r ".servers[$i].ruby_version" 
/usr/local/etc/puma.conf)
+               case $rb_env in
+                       "rbenv")
+                               su - $user -c "cd $dir && rbenv shell $rb_ver 
&& bundle exec puma -C $dir/config/puma.rb -d"
+                               ;;
+                       *)
+                               ;;
+               esac
+               i=$(( i + 1 ))
+       done
+}
+
+puma_stop()
+{
+    pkill ruby
+}
+
+puma_restart()
+{
+       server_count=$(/usr/local/bin/jq ".servers[] .ruby_env" 
/usr/local/etc/puma.conf | wc -l)
+       i=0     
+       while [ "$i" -lt "$server_count" ]; do
+               rb_env=$(/usr/local/bin/jq -r ".servers[$i].ruby_env" 
/usr/local/etc/puma.conf)
+               dir=$(/usr/local/bin/jq -r ".servers[$i].dir" 
/usr/local/etc/puma.conf)
+               user=$(/usr/local/bin/jq -r ".servers[$i].user" 
/usr/local/etc/puma.conf)
+               rb_ver=$(/usr/local/bin/jq -r ".servers[$i].ruby_version" 
/usr/local/etc/puma.conf)
+               case $rb_env in
+                       "rbenv")
+                               su - $user -c "cd $dir && pkill ruby && rbenv 
shell $ruby_version && bundle exec puma -C $dir/config/puma.rb -d"
+                               ;;
+                       *)
+                               ;;
+               esac
+               i=$(( i + 1 ))
+       done
+}
+
+load_rc_config $name
+run_rc_command "$1"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/tools/jungle/rc.d/puma.conf 
new/tools/jungle/rc.d/puma.conf
--- old/tools/jungle/rc.d/puma.conf     1970-01-01 01:00:00.000000000 +0100
+++ new/tools/jungle/rc.d/puma.conf     2018-07-13 18:08:52.000000000 +0200
@@ -0,0 +1,10 @@
+{
+       "servers" : [
+               {
+                       "dir": "/path/to/rails/project",
+                       "user": "deploy-user",
+                       "ruby_version": "ruby.version",
+                       "ruby_env": "rbenv"
+               }
+       ]
+}


Reply via email to