= Puma::Daemon :toc: :toclevels: 4 :sectnums: :icons: font image:https://github.com/kigster/puma-daemon/workflows/Ruby/badge.svg[link=https://github.com/kigster/puma-daemon/actions?query=workflow%3ARuby] image:https://codecov.io/gh/kigster/puma-daemon/branch/master/graph/badge.svg?token=asxarMSGbz[link=https://codecov.io/gh/kigster/puma-daemon] image:https://app.fossa.com/api/projects/git%2Bgithub.com%2Fkigster%2Fpuma-daemon.svg?type=shield[link=https://app.fossa.com/projects/git%2Bgithub.com%2Fkigster%2Fpuma-daemon?ref=badge_shield] image:https://badge.fury.io/rb/puma-daemon.svg["Gem Version", link="https://badge.fury.io/rb/puma-daemon"] image:https://codecov.io/gh/kigster/puma-daemon/commit/9ebd665764786a9815b159b699087148e19e671a/graphs/sunburst.svg[sunbirst] == Motivation In version 5.0 of the popular Ruby HTTP server https://github.com/puma/puma[Puma] the developers chose to https://github.com/puma/puma/pull/2170/files[drop the daemonization] support from Puma. They did that because the code wasn't actively maintained. Other and perhaps better options now exist (such as `systemd`, etc), not to mention that many people have switched to Kubernetes and Docker, where you generally want to start all servers in the foreground. And yet, on occasion, it was rather useful and straightforward to use the built-in daemonization feature that was cross-platform and is now gone. Some folks are still using this feature and are therefore stuck with Puma version 4, or must wrap Puma either in the `systemd` manifest or `launchctl plist` on Mac OS-X, or a Docker container. Well, **not anymore!** NOTE: Add this gem to your dependencies, and make a one line change either in your `config/puma.rb` file, or use `pumad` binary to start Puma as per usual, and you can even leave `-d` flags there (they are ignored when started via `pumad`, and Puma always goes to the background when started that way). One of the nice features of the old daemonization functionality was that it worked across all platforms. So, if you want to use the latest and greatest Puma 5+, but have it self-daemonize, this gem is for you. == Compatibility === Ruby Versions We did not restore the daemon functionality for JRuby; so at the moment this will work with the MRI distribution, and possibly others that support https://ruby-doc.org/core-2.6.1/Process.html#method-c-daemon[`Process.daemon(true, true)`]. For supported MRI Ruby Versions see the https://github.com/kigster/puma-daemon/blob/master/.github/workflows/main.yml#L10[Github Workflow] file. === Puma Versions Currently Puma versions 5 and 6 are supported. === Known Issues Please see the list of open issues on the https://github.com/kigster/puma-daemon/issues[Issues Page]. Any help is always welcomed. == Design Decisions This gem's goal was to surgically augment Puma's source code to restore daemonization by merely requiring `puma/daemon`. We accomplished this goal by adding the daemonization call to the routine `output_header()` which is invoked by both `Puma::Single` runner and the `Puma::Cluster` runner at the very beginning of the launch process. While relatively brittle, particularly if the future versions of Puma change this, this approach seems to work with the currently released version of Puma (5 and 6). If you run into problems, please https://github.com/kigster/puma-daemon/issues/new[submit an issue]. == Installation Add this line to your application's Gemfile: [source,ruby] ---- gem 'puma-daemon', require: false gem 'puma', '~> 5' # or 6 ---- In your `config/puma.rb`, eg. [source,ruby] ---- require 'puma/daemon' bind 'tcp://0.0.0.0:3000' workers 2 threads 4 daemonize ---- And then execute: $ bundle install $ bundle exec puma -C config/puma.rb Make sure you have `config.ru` Rackup file in the current folder. Checkout the shell script inside the `example` folder for more info. == Usage There were two ways you could daemonize Puma in the past: 1. By specifying `daemonize` or `daemonize(true)` in your config file. 2. By specifying `-d` or `--daemonize` on the command line. Both of these ways are supported, as long as you do `require 'puma/daemon'` in your puma config file, and — in the case of `-d` flag, you pass it to `pumad` executable, not `puma`. The recommended way to daemonize is via the provided `pumad` executable, or via the require in `puma.rb` and a subsequent call to `daemonize()` method. Please note that you must include `puma-daemon` in your Gemfile, but you may specify it as `require: false` — it will only activate if you explicitly require it in your Puma config file. === Examples Please see the https://github.com/kigster/puma-daemon/tree/master/example[`example`] directory in the source of the gem. It contains `single.sh` and `cluster.sh` scripts that boot Puma via `pumad` binary. === Daemonizing via the Config File If you want to specify `daemonize` in your config file, simply include `require 'puma/daemon'` at the top of your config file: [source,ruby] ---- # file: config/puma.rb require 'puma/daemon' port 3001 workers 3 threads 2,3 # accepts true or false, and if false is passed will NOT daemonize daemonize ---- With this method you can continue using the standard `puma` executable to get it started, but (and this is important) — **you must remove any `-d` or `--daemonize` from the command line**, or Puma v5 and above will fail with an error. Here is an example of daemonizing via the config file shown above, and using the regular `puma` binary: [source,bash] ---- ❯ cd example ❯ bundle exec puma -I ../lib -C $(pwd)/puma.rb -w 4 config.ru [62235] Puma starting in cluster mode... [62235] * Puma version: 6.1.1 (ruby 2.7.6-p219) ("The Way Up") [62235] * Min threads: 0 [62235] * Max threads: 16 [62235] * Environment: development [62235] * Master PID: 62235 [62235] * Puma Daemon: Daemonizing... [62235] * Gem: puma-daemon v0.2.0 [62235] * Gem: puma v6.1.1 [62258] * Workers: 4 [62258] * Restarts: (✔) hot (✔) phased [62258] * Listening on unix:///tmp/puma.sock [62258] * Listening on http://0.0.0.0:9292 ---- Note that using this method you can decide whether to daemonize or not by passing true or false to the `daemonize` method. === Daemonizing on the Command Line If you prefer to make a decision whether to daemonize or not on the command line, you only have to make one chance: replace `puma` with `pumad`. NOTE: We did not want to conflict with the `puma` gem by introducing another executable under the same name. The executable this gem provides is called `pumad` (where 'd' stands for daemon, and follows standard UNIX convention, as in eg `sshd`, `ftpd`, etc). If you replace `puma` with `pumad`, you no longer need to pass any additional command line flag (`-d` and `--daemonize`) to daemonize. You can continue passing them or you can remove them (these flags are stripped out before ARGV is passed onto Puma's CLI parser.) [source,bash] ---- ❯ cd example ❯ ../exe/pumad -C $(pwd)/puma.rb -w 0 config.ru Puma starting in single mode... * Puma version: 6.1.1 (ruby 2.7.6-p219) ("The Way Up") * Min threads: 0 * Max threads: 16 * Environment: development * PID: 63179 * Puma Daemon: Daemonizing... * Gem: puma-daemon v0.2.0 * Gem: puma v6.1.1 * Listening on unix:///tmp/puma.sock * Listening on http://0.0.0.0:9292 ---- As you can see, at the end it says "Daemonizing". If you start puma this way, you can still specify `daemonize(false)` in the configuration file to turn it off, but the default is to daemonize. Also, if you start with `pumad` you do not need to include `require 'puma/daemon'` in your configuration file, as the `pumad` binary loads all dependencies prior to parsing the config. == Development After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to https://rubygems.org[rubygems.org]. == Contributing Bug reports and pull requests are welcome on GitHub at https://github.com/kigster/puma-daemon. == License The gem is available as open source under the terms of the https://opensource.org/licenses/MIT[MIT License].