The puma plugin provides a systemd-based solution for starting, stopping, and restarting puma using socket activation for zero-downtime restarts. It is based on the best practices in the official puma documentation.
Tomo’s implementation installs puma as a user-level service using
systemctl --user. This allows puma to be installed, started, stopped, and restarted without a root user or
sudo. However, when provisioning the host you must make sure to run the following command as root to allow the puma process to continue running even after the tomo deploy user disconnects:
# run as root $ loginctl enable-linger <DEPLOY_USER>
Stdout and stderr of the puma process will be routed to syslog, as is the convention for systemd services. For Rails, it is recommended that you set
RAILS_LOG_TO_STDOUT=1 so that all Rails logs are handled this way (
tomo init configures this by default).
The tomo puma plugin assumes that your puma server will listen on a single TCP port for HTTP (not HTTPS) traffic. In other words, HTTPS termination will be handled by e.g. Nginx or a separate load balancer.
||The number of seconds that the puma:check_active task will wait for puma to respond before timing out.||
||Hostname / IP address that puma should listen on||
||TCP port that puma should listen on||
||Name of the systemd service that manages the puma server||
||Name of the systemd socket that is used for socket activation of the puma service||
||Path on the remote host where the systemd puma service configuration file will be created||
||Path on the remote host where the systemd puma socket configuration file will be created||
||Local path of the ERB template to use to create the the systemd puma service configuration file||service.erb|
||Local path of the ERB template to use to create the the systemd puma socket configuration file||socket.erb|
Configures systemd to manage puma. This means that puma will automatically be restarted if it crashes, or if the host is rebooted. This task essentially does three things:
- Installs a
- Installs a
puma.servicesystemd unit that depends on the socket
- Enables these units using
systemctl --user enable
Note that these units will be installed and run for the deploy user. You can use
:puma_systemd_service_template_path to provide your own templates and customize how puma and systemd are configured.
puma:setup_systemd is intended for use as a setup task. It must be run before puma can be started during a deploy.
Restarts the puma service via systemd. This starts puma if it isn’t running already. The systemd socket remains running while puma itself is restarted. In other words, incoming requests will continue to connect and queue while puma restarts. This is a “zero-downtime restart”.
Puma will be configured to listen on
:puma_port, with the
config/puma.rb file within the Rails app providing the remainder of the configuration. The default port is 3000. Puma is started using this command:
bundle exec --keep-file-descriptors puma -C config/puma.rb -b tcp://0.0.0.0:3000
puma:restart is intended for use in a deploy, immediately following core:symlink_current to ensure that the new version of the Rails app is activated.
This task queries systemd and executes a
curl test to verify that puma is active and listening on
:puma_port. Because puma is run in the background, it is not immediately obvious after starting or restarting puma via systemd as to whether it booted successfully, or if it crashed. This is where the
puma:check_active task can help. If puma is not working it will fail and show puma’s log output for easier troubleshooting.
puma:check_active is intended for use as a deploy task, immediately following puma:restart to verify that puma restarted successfully.
Starts the puma socket and service via systemd, if they aren’t running already. Equivalent to:
systemctl --user start puma.socket puma.service
Stops the puma socket and service via systemd. Equivalent to:
systemctl --user stop puma.socket puma.service
Reports the status of the puma socket and service via systemd. Equivalent to:
systemctl --user status puma.socket puma.service
$ tomo run puma:status tomo run v0.10.0 → Connecting to firstname.lastname@example.org • puma:status systemctl --user status puma_example.socket puma_example.service ● puma_example.socket - Puma HTTP Server Accept Sockets for example Loaded: loaded (/home/deployer/.config/systemd/user/puma_example.socket; enabled; vendor preset: enabled) Active: active (running) since Thu 2019-10-24 09:41:53 UTC; 1 weeks 2 days ago Listen: 0.0.0.0:3000 (Stream) ● puma_example.service - Puma HTTP Server for example Loaded: loaded (/home/deployer/.config/systemd/user/puma_example.service; enabled; vendor preset: enabled) Active: active (running) since Fri 2019-11-01 15:46:10 UTC; 1 day 10h ago Main PID: 14513 (bundle) CGroup: /email@example.com/puma_example.service └─14513 puma 4.2.1 (tcp://0.0.0.0:3000) 
journalctl (part of systemd) to view the log output of the puma service. This task is intended for use as a run task and accepts command-line arguments. The arguments are passed through to the
journalctl command. For example:
$ tomo run -- puma:log -f
Will run this remote script:
journalctl -q --user-unit=puma.service -f
A convenience method for tailing the puma logs. Equivalent to
tomo run -- puma:log -f