diff --git a/README.md b/README.md index 6b375d7e1b..86e2cf96ca 100644 --- a/README.md +++ b/README.md @@ -13,11 +13,19 @@ Puma is a **simple, fast, multi-threaded, and highly concurrent HTTP 1.1 server ## Built For Speed & Concurrency -Puma processes requests using a C-optimized Ragel extension (inherited from Mongrel) that provides fast, accurate HTTP 1.1 protocol parsing in a portable way. Puma then serves the request using a thread pool. Each request is served in a separate thread, so truly concurrent Ruby implementations (JRuby, Rubinius) will use all available CPU cores. +Puma processes requests using a C-optimized Ragel extension (inherited from +Mongrel) that provides fast, accurate HTTP 1.1 protocol parsing in a portable way. +Puma then serves the request using a thread pool. Each request is served in a +separate thread, so truly concurrent Ruby implementations (JRuby, Rubinius) will +use all available CPU cores. -Puma was designed to be the go-to server for [Rubinius](https://rubinius.com), but also works well with JRuby and MRI. +Puma was designed to be the go-to server for [Rubinius](https://rubinius.com), +but also works well with JRuby and MRI. -On MRI, there is a Global VM Lock (GVL) that ensures only one thread can run Ruby code at a time. But if you're doing a lot of blocking IO (such as HTTP calls to external APIs like Twitter), Puma still improves MRI's throughput by allowing IO waiting to be done in parallel. +On MRI, there is a Global VM Lock (GVL) that ensures only one thread can run Ruby +code at a time. But if you're doing a lot of blocking IO (such as HTTP calls to +external APIs like Twitter), Puma still improves MRI's throughput by allowing IO +waiting to be done in parallel. ## Quick Start @@ -26,8 +34,11 @@ $ gem install puma $ puma ``` -Without arguments, puma will look for a rackup (.ru) file in -working directory called `config.ru`. +Without arguments, puma will look for a rackup (.ru) file in working directory +called `config.ru`. + +Puma expects to find OpenSSL development files when installed/compiled. If you +want to compile it without ssl support, set ENV['DISABLE_SSL']. ## Frameworks @@ -41,7 +52,8 @@ Start your server with the `rails` command: $ rails server ``` -Many configuration options and Puma features are not available when using `rails server`. It is recommended that you use Puma's executable instead: +Many configuration options and Puma features are not available when using +`rails server`. It is recommended that you use Puma's executable instead: ``` $ bundle exec puma @@ -64,34 +76,51 @@ configure { set :server, :puma } ## Configuration -Puma provides numerous options. Consult `puma -h` (or `puma --help`) for a full list of CLI options, or see [dsl.rb](https://github.com/puma/puma/blob/master/lib/puma/dsl.rb). +Puma provides numerous options. Consult `puma -h` (or `puma --help`) for a full +list of CLI options, or see +[dsl.rb](https://github.com/puma/puma/blob/master/lib/puma/dsl.rb). You can also find several configuration examples as part of the [test](https://github.com/puma/puma/tree/master/test/config) suite. ### Thread Pool -Puma uses a thread pool. You can set the minimum and maximum number of threads that are available in the pool with the `-t` (or `--threads`) flag: +Puma uses a thread pool. You can set the minimum and maximum number of threads +that are available in the pool with the `-t` (or `--threads`) flag: ``` $ puma -t 8:32 ``` -Puma will automatically scale the number of threads, from the minimum until it caps out at the maximum, based on how much traffic is present. The current default is `0:16` and on MRI is `0:5`. Feel free to experiment, but be careful not to set the number of maximum threads to a large number, as you may exhaust resources on the system (or cause contention for the Global VM Lock, when using MRI). +Puma will automatically scale the number of threads, from the minimum until it +caps out at the maximum, based on how much traffic is present. The current +default is `0:16` and on MRI is `0:5`. Feel free to experiment, but be careful +not to set the number of maximum threads to a large number, as you may exhaust +resources on the system (or cause contention for the Global VM Lock, when using MRI). -Be aware that additionally Puma creates threads on its own for internal purposes (e.g. handling slow clients). So, even if you specify -t 1:1, expect around 7 threads created in your application. +Be aware that additionally Puma creates threads on its own for internal purposes +(e.g. handling slow clients). So, even if you specify -t 1:1, expect around +7 threads created in your application. ### Clustered mode -Puma also offers "clustered mode". Clustered mode `fork`s workers from a master process. Each child process still has its own thread pool. You can tune the number of workers with the `-w` (or `--workers`) flag: +Puma also offers "clustered mode". Clustered mode `fork`s workers from a master +process. Each child process still has its own thread pool. You can tune the +number of workers with the `-w` (or `--workers`) flag: ``` $ puma -t 8:32 -w 3 ``` -Note that threads are still used in clustered mode, and the `-t` thread flag setting is per worker, so `-w 2 -t 16:16` will spawn 32 threads in total, with 16 in each worker process. +Note that threads are still used in clustered mode, and the `-t` thread flag +setting is per worker, so `-w 2 -t 16:16` will spawn 32 threads in total, with 16 +in each worker process. -In clustered mode, Puma can "preload" your application. This loads all the application code *prior* to forking. Preloading reduces total memory usage of your application via an operating system feature called [copy-on-write](https://en.wikipedia.org/wiki/Copy-on-write) (Ruby 2.0+ only). Use the `--preload` flag from the command line: +In clustered mode, Puma can "preload" your application. This loads all the +application code *prior* to forking. Preloading reduces total memory usage of +your application via an operating system feature called +[copy-on-write](https://en.wikipedia.org/wiki/Copy-on-write) (Ruby 2.0+ only). +Use the `--preload` flag from the command line: ``` $ puma -w 3 --preload @@ -105,7 +134,8 @@ workers 3 preload_app! ``` -Additionally, you can specify a block in your configuration file that will be run on boot of each worker: +Additionally, you can specify a block in your configuration file that will be +run on boot of each worker: ```ruby # config/puma.rb @@ -114,9 +144,10 @@ on_worker_boot do end ``` -This code can be used to setup the process before booting the application, allowing -you to do some Puma-specific things that you don't want to embed in your application. -For instance, you could fire a log notification that a worker booted or send something to statsd. This can be called multiple times. +This code can be used to setup the process before booting the application, +allowing you to do some Puma-specific things that you don't want to embed in your +application. For instance, you could fire a log notification that a worker booted +or send something to statsd. This can be called multiple times. `before_fork` specifies a block to be run before workers are forked: @@ -127,14 +158,18 @@ before_fork do end ``` -Preloading can’t be used with phased restart, since phased restart kills and restarts workers one-by-one, and preload_app copies the code of master into the workers. +Preloading can’t be used with phased restart, since phased restart kills and +restarts workers one-by-one, and preload_app copies the code of master into the +workers. ### Error handling -If puma encounters an error outside of the context of your application, it will respond with a 500 and a simple -textual error message (see `lowlevel_error` in [this file](https://github.com/puma/puma/blob/master/lib/puma/server.rb)). -You can specify custom behavior for this scenario. For example, you can report the error to your third-party -error-tracking service (in this example, [rollbar](https://rollbar.com)): +If puma encounters an error outside of the context of your application, it will +respond with a 500 and a simple textual error message (see `lowlevel_error` in +[this file](https://github.com/puma/puma/blob/master/lib/puma/server.rb)). +You can specify custom behavior for this scenario. For example, you can report +the error to your third-party error-tracking service (in this example, +[rollbar](https://rollbar.com)): ```ruby lowlevel_error_handler do |e| @@ -157,7 +192,8 @@ To use a UNIX Socket instead of TCP: $ puma -b unix:///var/run/puma.sock ``` -If you need to change the permissions of the UNIX socket, just add a umask parameter: +If you need to change the permissions of the UNIX socket, just add a umask +parameter: ``` $ puma -b 'unix:///var/run/puma.sock?umask=0111' @@ -171,7 +207,8 @@ $ puma -b 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert' #### Controlling SSL Cipher Suites -To use or avoid specific SSL cipher suites, use `ssl_cipher_filter` or `ssl_cipher_list` options. +To use or avoid specific SSL cipher suites, use `ssl_cipher_filter` or +`ssl_cipher_list` options. ##### Ruby: @@ -185,7 +222,8 @@ $ puma -b 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert&ssl_cipher_fil $ 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. +See https://www.openssl.org/docs/man1.0.2/apps/ciphers.html for cipher filter +format and full list of cipher suites. Disable TLS v1 with the `no_tlsv1` option: @@ -195,15 +233,21 @@ $ puma -b 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert&no_tlsv1=true' ### Control/Status Server -Puma has a built-in status and control app that can be used to query and control Puma. +Puma has a built-in status and control app that can be used to query and control +Puma. ``` $ 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 control token (in this case, `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 status app has available. +Puma will start the control server on localhost port 9293. All requests to the +control server will need to include control token (in this case, `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 status app has available. -You can also interact with the control server via `pumactl`. This command will restart Puma: +You can also interact with the control server via `pumactl`. This command will +restart Puma: ``` $ pumactl --control-url 'tcp://127.0.0.1:9293' --control-token foo restart @@ -219,38 +263,58 @@ You can also provide a configuration file with the `-C` (or `--config`) flag: $ puma -C /path/to/config ``` -If no configuration file is specified, Puma will look for a configuration file at `config/puma.rb`. If an environment is specified, either via the `-e` and `--environment` flags, or through the `RACK_ENV` or the `RAILS_ENV` environment variables, Puma looks for configuration at `config/puma/.rb`. +If no configuration file is specified, Puma will look for a configuration file at +`config/puma.rb`. If an environment is specified, either via the `-e` and +`--environment` flags, or through the `RACK_ENV` or the `RAILS_ENV` environment +variables, Puma looks for configuration at `config/puma/.rb`. -If you want to prevent Puma from looking for a configuration file in those locations, provide a dash as the argument to the `-C` (or `--config`) flag: +If you want to prevent Puma from looking for a configuration file in those +locations, provide a dash as the argument to the `-C` (or `--config`) flag: ``` $ puma -C "-" ``` -The other side-effects of setting the environment are whether to show stack traces (in `development` or `test`), and setting RACK_ENV may potentially affect middleware looking for this value to change their behavior. The default puma RACK_ENV value is `development`. You can see all config default values [here](https://github.com/puma/puma/blob/12d1706ddc71b89ed2ee26275e31c788e94ff541/lib/puma/configuration.rb#L170). +The other side-effects of setting the environment are whether to show stack traces +(in `development` or `test`), and setting RACK_ENV may potentially affect +middleware looking for this value to change their behavior. The default puma +`RACK_ENV` value is `development`. You can see all config default values +[here](https://github.com/puma/puma/blob/4ea724e8e92/lib/puma/configuration.rb#L180). -Check out [dsl.rb](https://github.com/puma/puma/blob/master/lib/puma/dsl.rb) to see all available options. +Check out [dsl.rb](https://github.com/puma/puma/blob/master/lib/puma/dsl.rb) to +see all available options. ## Restart -Puma includes the ability to restart itself. When available (MRI, Rubinius, JRuby), Puma performs a "hot restart". This is the same functionality available in *Unicorn* and *NGINX* which keep the server sockets open between restarts. This makes sure that no pending requests are dropped while the restart is taking place. +Puma includes the ability to restart itself. When available (MRI, Rubinius, JRuby), +Puma performs a "hot restart". This is the same functionality available in *Unicorn* +and *NGINX* which keep the server sockets open between restarts. This makes sure +that no pending requests are dropped while the restart is taking place. For more, see the [restart documentation](https://github.com/puma/puma/blob/master/docs/restart.md). ## Signals -Puma responds to several signals. A detailed guide to using UNIX signals with Puma can be found in the [signals documentation](https://github.com/puma/puma/blob/master/docs/signals.md). +Puma responds to several signals. A detailed guide to using UNIX signals with +Puma can be found in the +[signals documentation](https://github.com/puma/puma/blob/master/docs/signals.md). ## Platform Constraints Some platforms do not support all Puma features. - * **JRuby**, **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. Also, cluster mode is not supported due to a lack of fork(2). + * **JRuby**, **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. Also, cluster mode is not supported + due to a lack of fork(2). * **Windows**: Cluster mode is not supported due to a lack of fork(2). ## Known Bugs -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: +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.2.9 2.2.10 2.3.4 2.4.1).include? RUBY_VERSION @@ -263,10 +327,11 @@ end ## Deployment -Puma has support for Capistrano with an [external gem](https://github.com/seuros/capistrano-puma). +Puma has support for Capistrano with an +[external gem](https://github.com/seuros/capistrano-puma). -It is common to use process monitors with Puma. Modern process monitors like systemd or upstart -provide continuous monitoring and restarts for increased +It is common to use process monitors with Puma. Modern process monitors like +systemd or upstart provide continuous monitoring and restarts for increased reliability in production environments: * [docs/jungle](https://github.com/puma/puma/tree/master/docs/jungle) for rc.d and upstart @@ -276,14 +341,19 @@ reliability in production environments: ### Plugins -* [puma-heroku](https://github.com/puma/puma-heroku) — default Puma configuration for running on Heroku -* [puma-metrics](https://github.com/harmjanblok/puma-metrics) — export Puma metrics to Prometheus -* [puma-plugin-statsd](https://github.com/yob/puma-plugin-statsd) — send Puma metrics to statsd -* [puma-plugin-systemd](https://github.com/sj26/puma-plugin-systemd) — deeper integration with systemd for notify, status and watchdog +* [puma-heroku](https://github.com/puma/puma-heroku) — default Puma configuration + for running on Heroku +* [puma-metrics](https://github.com/harmjanblok/puma-metrics) — export Puma + metrics to Prometheus +* [puma-plugin-statsd](https://github.com/yob/puma-plugin-statsd) — send Puma + metrics to statsd +* [puma-plugin-systemd](https://github.com/sj26/puma-plugin-systemd) — deeper + integration with systemd for notify, status and watchdog ### Monitoring -* [puma-status](https://github.com/ylecuyer/puma-status) — Monitor CPU/Mem/Load of running puma instances from the CLI +* [puma-status](https://github.com/ylecuyer/puma-status) — Monitor CPU/Mem/Load + of running puma instances from the CLI ## Contributing @@ -293,4 +363,5 @@ Find details for contributing in the [contribution guide]. ## License -Puma is copyright Evan Phoenix and contributors, licensed under the BSD 3-Clause license. See the included LICENSE file for details. +Puma is copyright Evan Phoenix and contributors, licensed under the +BSD 3-Clause license. See the included LICENSE file for details.