02 July 2013 Puma 2 Updates:
I’ve been playing around with Heroku a lot lately and noticed they recommend using Thin for your production server when running Rails. In recent months I’ve grown attached to Puma (for no qualified reasons) and wanted to see if I can get a Rails app running on Heroku’s cedar stack with Puma instead. It turned out to be really, really simple.
First create a new rails app, heroku app, and initialize a git repo:
$ rails new heroku-puma create ... $ cd heroku-puma $ heroku create Creating high-day-4093... done, stack is cedar http://high-day-4093.herokuapp.com/ | email@example.com:high-day-4093.git $ git init $ git remote add heroku firstname.lastname@example.org:high-day-4093.git
Launch your favorite editor and make some standard adjustments in your
Gemfile, just as a demonstration:
... gem 'sqlite3' ...
... gem 'thin' ...
Back in the terminal, add your files to the git repo and make your first commit, then push it up to Heroku:
$ git add . $ git commit -m "Initial import, using Thin server" $ git push heroku master -----> Heroku receiving push -----> Ruby/Rails app detected -----> Installing dependencies using Bundler version 1.2.0.pre Running: bundle install --without development:test --path vendor/bundle --binstubs bin/ --deployment Fetching gem metadata from https://rubygems.org/....... ... Installing thin (1.4.1) with native extensions ... -----> Launching... done, v4 http://high-day-4093.herokuapp.com deployed to Heroku $
Now that your app is launched, do a quick
curl call and confirm it’s
$ curl -I http://high-day-4093.herokuapp.com HTTP/1.1 200 OK [...] Server: thin 1.4.1 codename Chromeo [..] $
Hooray, we’re running Thin! You can see this in the Server header that Thin sets. Except, we want to run Puma…
Cedar introduced a new way to think about scaling your app; “the process model”. It’s a generalized approach to managing processes across Heroku’s distributed environment, allowing you to tweak how and what gets run via a Procfile. Here we’ll create a simple
Procfile and tell our app to run with Puma instead of Thin.
First, swap out Thin for Puma in your
... gem 'puma' ...
[^proc]Then add a file named
Procfile to the root of your project and add the following:
web: bundle exec puma -p $PORT -e $RACK_ENV -t 0:5
Those are the instructions Heroku will use to run your
Making sure to add the new
Procfile to your repo, commit your changes
and push to Heroku again:
$ git add Procfile $ git add Gemfile $ git commit -m "Use Puma via a Procfile" $ git push heroku master -----> Heroku receiving push -----> Ruby/Rails app detected -----> Installing dependencies using Bundler version 1.2.0.pre Running: bundle install --without development:test --path vendor/bundle --binstubs bin/ --deployment Fetching gem metadata from https://rubygems.org/....... ... Installing puma (1.4.0) with native extensions ... -----> Launching... done, v5 http://high-day-4093.herokuapp.com deployed to Heroku
Now we run our
curl command again:
$ curl -I http://high-day-4093.herokuapp.com HTTP/1.1 200 OK [...] $
Hooray, we’re not running Thin! Except it doesn’t say we’re running Puma either… I suppose Puma doesn’t report itself like Thin and WEBrick do.
Now if you run
heroku ps you should see you have 1 web dyno running,
and the statement used to run it:
$ heroku ps === web: bundle exec puma -p $PORT -e $RACK_ENV -t 0:5 web.1: up for 2m
Congratulations, you’re running Puma! Note that Puma is said to really shine with Rubinius and JRuby where it can utilize multiple threads. Still, it should give you some benefits on MRI as well.
As you continue to fine tune your Puma setup, you may find yourself with
more than a few flags and switches in your invocation (the
web: part of
Procfile in this case). Puma lets you specify a configuration file
for all this, using the
web: bundle exec puma -p $PORT -C ./config/puma.rb
# config/puma.rb environment ENV['RACK_ENV'] threads 0,5
With it’s 2.0 release, Puma learned some new tricks, key being the
addition of Clustered
Mode. Puma gains a level of concurrency by spawning workers to handle requests,
each worker with it’s own set of threads. You enable clustered mode with
--workers flag, providing the number of workers you’d like
to spawn. To enable this on Heroku, simply update your
web: bundle exec puma -p $PORT -e $RACK_ENV -w 3 -t 0:5
workers to your
# config/puma.rb environment ENV['RACK_ENV'] threads 0,5 workers 3
You can optionally choose to preload your application before spinning up
your workers. Use the
--preload flag or call
preload_app! in your
Finally, you can hook into your workers before they boot with the
on_worker_boot method in your config file. An example of something to
do here is if you’re preloading your application, you’ll want to
establish your ActiveRecord connections here:
# config/puma.rb environment ENV['RACK_ENV'] threads 0,5 workers 3 preload_app! on_worker_boot do ActiveSupport.on_load(:active_record) do ActiveRecord::Base.establish_connection end end
Now get hacking.