When Rails 4 was released it offered a bunch new features and deprecations :
You can see that thread safety is since on by default so a Rack server can safely create threads for your Rails app rather than forking process and waste cpu cycles and memory.
If you didn’t switch to a Rack compatible server that can efficiently makes use of threads then it’s time to do so. I decided to switch from Unicorn (process forks) to Puma which is thread oriented.
You’ll see a great memory improvement if you switch and you’ll be able to use threads effectively in your app if you want to since Rails is now fully thread-safe.
Here are the three steps to have a Nginx / Puma / Capistrano stack up & running for a Rails app.
Configuring Nginx
Common config
You probably already have this setted up if you were using Nginx / Unicorn stack but here is a quick reminder for Nginx global configuration:
/etc/nginx/nginx.conf
user www-data;
worker_processes 8;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
multi_accept on;
}
http {
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 5;
types_hash_max_size 2048;
server_names_hash_max_size 512;
server_names_hash_bucket_size 128;
include /etc/nginx/mime.types;
default_type application/octet-stream;
##
# Logging Settings
##
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
##
# Gzip Settings
##
gzip on;
gzip_disable "msie6";
gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
##
# Virtual Host Configs
##
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
Pretty straigth forward, nothing new here.
Vhost file
For example /etc/nginx/sites-enabled/01-bounga
# Upstream server (Puma socket)
upstream bounga {
server unix:/var/www/bounga/shared/sockets/puma.sock;
}
# Redirect non-www requests to www host
server {
server_name bounga.org;
return 301 $scheme://www.bounga.org$request_uri;
}
# Config for vhost
server {
listen 80;
server_name www.bounga.org;
access_log /var/log/nginx/bounga.access.log;
error_log /var/log/nginx/bounga.error.log;
root /var/www/bounga/current/public;
# direct to maintenance if this file exists
if (-f $document_root/system/maintenance.html) {
rewrite ^(.*)$ /system/maintenance.html last;
break;
}
# assets caching
location ~ ^/(assets)/ {
access_log off;
gzip_static on;
expires max;
add_header Cache-Control public;
add_header Last-Modified "";
add_header ETag "";
open_file_cache max=1000 inactive=500s;
open_file_cache_valid 600s;
open_file_cache_errors on;
break;
}
# serve static file directly
try_files $uri/index.html $uri @bounga;
# App proxying
location @bounga {
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://bounga;
}
error_page 500 502 503 504 /500.html;
keepalive_timeout 10;
location = /favicon.ico {
expires max;
add_header Cache-Control public;
}
}
Once again nothing new here. You may have to change some values or add some directives depending on your app behaviour but this config example should work in most usecases.
Configuring Puma
Puma default settings are safe so you can use it in your Rails apps without even creating a config file. It will work just fine thanks to capistrano3-puma
integration which we’ll talk about later.
Nonetheless maybe you’ll need to tweak your config so here are some insigths to be able to tune Puma behaviour. This is a very well documented example provided by Puma development team that you can put in config/puma.rb
.
Note that you’ll be able to set most of these parameters right in your Capistrano config file, per environment which seems better to me.
Configuring Capistrano
Now we need to setup Capistrano to be able to handle Puma on deploys.
First you’ll need to add a gem to your Gemfile
:
gem 'capistrano3-puma'
Then in your Capfile
you’ll have to require it:
require 'capistrano/puma'
It will add some tasks to you Capistrano tasks:
$ bundle exec cap puma:start
$ bundle exec cap puma:restart
$ bundle exec cap puma:stop
$ bundle exec cap puma:phased_restart
Now we’re done! Everything else is handled for us. We can tweak the default behaviour but in most cases it will work as expected, for example bundle exec cap deploy
will restart Puma for us at the end of the deploy.
Puma, a developer’s best friend
Puma seems to be the way to go these days if you want to use a proxy and a Rack server. It allows fast and effecient concurrency. Trust me you won’t regret this choice.
Share on
Twitter Facebook LinkedInHave comments or want to discuss this topic?
Send an email to ~bounga/public-inbox@lists.sr.ht