-
-
Notifications
You must be signed in to change notification settings - Fork 530
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Replace Unicorn with Puma #501
Conversation
def configure_unicorn | ||
copy_file 'unicorn.rb', 'config/unicorn.rb' | ||
def configure_puma | ||
copy_file 'puma.rb', 'config/puma.rb' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prefer double-quoted strings unless you need single quotes to avoid extra backslashes for escaping.
👍 |
Okay before merging I'm going to try actually running an app with this server and these config. |
And leave this at least a day. |
@@ -1,2 +1,2 @@ | |||
web: bundle exec unicorn -p $PORT -c ./config/unicorn.rb | |||
web: bundle exec rails serve Puma -p $PORT -c ./config/puma.rb |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why rails serve Puma
rather than bundle exec puma
per https://devcenter.heroku.com/articles/deploying-rails-applications-with-the-puma-web-server?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I pulled it from https://github.com/puma/puma#rails, and the move closer to the traditional Rails flow appeals to me. I'll check into actual differences when I try this in a fresh app.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe some details here: http://stackoverflow.com/a/21218048 That answer
makes sense to me but I wonder why Heroku's docs are different, if there's
anything platform-specific that makes the Heroku docs version better on
Heroku. Maybe @schneems or @hone knows?
On Mon, Jan 26, 2015 at 3:42 PM, Caleb Thompson notifications@github.com
wrote:
In templates/Procfile
#501 (comment):@@ -1,2 +1,2 @@
-web: bundle exec unicorn -p $PORT -c ./config/unicorn.rb
+web: bundle exec rails serve Puma -p $PORT -c ./config/puma.rbI pulled it from https://github.com/puma/puma#rails.
—
Reply to this email directly or view it on GitHub
https://github.com/thoughtbot/suspenders/pull/501/files#r23575253.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think there are differences really. There were some conflicts with some flags being parsed and passed to rails
, but i guess those got sorted out 🤷 . The main reason we're doing it that way is so anyone running straight Rack can copy most of the article verbatim and still have it work. Same command on every project.
Btw, i think serve
should be server
. Also have you considered providing default config values? So you can run without a port specified i.e. -p ${PORT:-3000}
Definitely want to hear reports of people using this config in production before we merge this in. Otherwise, makes sense and thanks for the PR. Good to squash and merge at your discretion. |
@@ -1,30 +0,0 @@ | |||
# https://devcenter.heroku.com/articles/rails-unicorn | |||
|
|||
worker_processes (ENV["UNICORN_WORKERS"] || 3).to_i |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@croaky we lost something here too. Any idea what?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Found it.
dd7dcdc
to
211517e
Compare
timeout: 5000 | ||
|
||
test: | ||
<<: *default | ||
database: <%= app_name %>_test | ||
|
||
production: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want this for staging and production? Not sure if there's a better way, but maybe something like:
staging: &deploy
<<: *default
url: <%%= ENV.fetch("DATABASE_URL") %>
production:
<<: *deploy
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think so. We'd have to have that URL instead of the rest of this config.
This works because heroku provides this URL, Rails knows how to parse it, and we just override a single setting (or set it in the first place, in this case).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, I wonder why we need to set url
to DATABASE_URL
at all. I thought Heroku already did that? Can we drop this line and only set pool
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a best practice. Rails does merge in DATABASE_URL into your config but explicit is better than implicit imho. As of 4.1 all this behavior is in Rails, Heroku isn't doing anything other than setting the env var
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like you might be right:
database.yml present
DATABASE_URL present
=> Merged intourl
sub key. If both specifyurl
sub key, thedatabase.yml
url
sub key "wins". If other paramatersadapter
ordatabase
are specified in YAML,
they are discarded as theurl
sub key "wins".
rails/rails#13463 (comment) linked from rails/rails#13578
Which would mean that we can't use defaults in production if it specifies database names, etc. but can set things like pool to be merged in.
These are the keys we already have which I think we can set safely, without overriding DATABASE_URL:
encoding: utf8
min_messages: warning
pool: 2
timeout: 5000
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in ba12e09
This is great. I've been thinking we should be switching to Puma for a while, and I've always been uncomfortable with the slow client problem. I think Upcase is a good mid-traffic app to try this on. I can hopefully try it out this week, but if you're looking for a test project, feel free to open a pull request there. |
Thanks, Joe. |
@@ -1,2 +1,2 @@ | |||
web: bundle exec unicorn -p $PORT -c ./config/unicorn.rb | |||
web: bundle exec rails server Puma -p ${PORT:-3000} -c ./config/puma.rb |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems to break starting the app with Foreman. While running bundle exec rails s puma
works, passing the config file will break with undefined method
workers'`. This is a known issue (see puma/puma#512) and the example Procfile in the Heroku docs uses puma directly. Of course, the downside to that solution is losing logging...
Changing the Procfile to web: bundle exec puma -C ./config/puma.rb
does boot the app loading the config.
but will also throw a thread warning related to the connection pool (discussion around similar issues can be found in puma/puma#614).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why default to 3000
? That seems like an additional (unnecessary) change. Is it something to do with Puma? Doesn't foreman handle $PORT
for us?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch. We should either re-use def port
from lib/suspenders/app_builder.rb or rely on Foreman.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the example Procfile in the Heroku docs uses puma directly. Of course, the downside to that solution is losing logging...
@pedrosmmoreira Curious what you mean by "losing logging"? The Rails app itself will still log to whatever mechanism you've set the log to (STDOUT
when running on Heroku). Are there other logs I'm not aware of or missing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@stevenharman I might not have explained myself correctly. Using Puma directly runs the server unaware of the rails environment: this modifies logging behaviour, if I'm not mistaken.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem with -c ./config/puma.rb
is that the rails server command is expecting a rackup file there, e.g. config.ru
by default.
To do what you want, what you basically need to do is:
require ::File.expand_path('../config/environment', __FILE__)
require "puma"
require "puma/configuration"
puma_config_file = ::File.expand_path('../config/puma.rb', __FILE__)
Puma::Configuration.new(config_file: puma_config_file).load
run Rails.application
which doesn't work, so we'd need to ask the puma peeps how to configure puma from a rackup file
Perhaps by interacting with Rails::Server#server
(which subclasses Rack::Server
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think the rackup file is supposed to know about the server:
# This file is used by Rack-based servers to start the application.
require ::File.expand_path('../config/environment', __FILE__)
run CodeTriage::Application
What's the problem with manually using the puma
command in the web:
line of the Procfile
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Works for me. Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
`rake dev` spun up a server on 9292 using webrick. Webrick is slow and old. Let's upgrade to puma, per recommendation from the people at Heroku: https://devcenter.heroku.com/changelog-items/594 `puma.rb` pulled from thoughtbot's suspenders project here: thoughtbot/suspenders#501
`rake dev` spun up a server on 9292 using webrick. Webrick is slow and old. Let's upgrade to puma, per recommendation from the people at Heroku: https://devcenter.heroku.com/changelog-items/594 `puma.rb` pulled from thoughtbot's suspenders project here: thoughtbot/suspenders#501
timeout: 5000 | ||
|
||
test: | ||
<<: *default | ||
database: <%= app_name %>_test | ||
|
||
production: | ||
url: <%%= ENV.fetch("DATABASE_URL") %> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When running this in my development env it chokes because I don't have DATABASE_URL
set. Suffice it to say - on heroku this will be set, and locally it's not needed. A change to <%%= ENV.fetch("DATABASE_URL", "") %>
fixed this for me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @jayroh. <3 <3
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hollaaaaaaaaaa @croaky!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in a78dc1e
Since we now never specify the port in either puma.rb or the Procfile, will Puma still work with Foreman? |
Foreman uses port 5000 by default. Also even if you start using |
So, this will work with Foreman even if I use a custom port like |
`rake dev` spun up a server on 9292 using webrick. Webrick is slow and old. Let's upgrade to puma, per recommendation from the people at Heroku: https://devcenter.heroku.com/changelog-items/594 `puma.rb` pulled from thoughtbot's suspenders project here: thoughtbot/suspenders#501
`rake dev` spun up a server on 9292 using webrick. Webrick is slow and old. Let's upgrade to puma, per recommendation from the people at Heroku: https://devcenter.heroku.com/changelog-items/594 `puma.rb` pulled from thoughtbot's suspenders project here: thoughtbot/suspenders#501
We've run into issues using My understanding is that puma can be configured to have a single, non-forking worker in development, which would smooth over the difficulties with I'm willing to try out puma on my next |
I've used Puma a few times in the last month or so, for example on a production app serving an API for an active iPhone app. This change in general seems well-vetted now in prod. @seandoyle I think you can set WEB_CONCURRENCY and MAX_THREADS to 1 each in development? Maybe we add that to .sample.env? https://devcenter.heroku.com/articles/deploying-rails-applications-with-the-puma-web-server#config |
@drapergeek and I tried setting I'll try out puma with |
`rake dev` spun up a server on 9292 using webrick. Webrick is slow and old. Let's upgrade to puma, per recommendation from the people at Heroku: https://devcenter.heroku.com/changelog-items/594 `puma.rb` pulled from thoughtbot's suspenders project here: thoughtbot/suspenders#501
`rake dev` spun up a server on 9292 using webrick. Webrick is slow and old. Let's upgrade to puma, per recommendation from the people at Heroku: https://devcenter.heroku.com/changelog-items/594 `puma.rb` pulled from thoughtbot's suspenders project here: thoughtbot/suspenders#501
@seanpdoyle How has Puma been running for FormKeep? Any settings in this PR that you recommend as different defaults? |
@calebthompson Possible to push this over the finish line? Seems like we're ready. @halogenandtoast had one piece of feedback above. |
👍 |
encoding: utf8 | ||
min_messages: warning | ||
pool: <%%= [ENV.fetch("MAX_THREADS", 2), ENV.fetch("DB_POOL", 2)].max %> | ||
timeout: 5000 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this a reasonable timeout for production?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't think of a reason it wouldn't be. Can you?
@calebthompson I think you're available tomorrow? Possible to do a final review, merge this, and release a new version? Seen a couple of brand-new apps recently getting slow client errors with Unicorn, Heroku, two dynos, almost no traffic. Might be something worth grabbing from https://github.com/thoughtbot/hound/pull/846/files |
Ready for final review. |
I'm content with this. If it's a 👍 please go ahead and merge this. |
Looks good to me. |
> Heroku now recommends using the Puma webserver. The previously > recommended webserver, Unicorn, is susceptible to slow client attacks. https://devcenter.heroku.com/changelog-items/594 * Specify deploy settings - Set values that DATABASE_URL won't override / set - Add staging - Use max of thread count or db pool, since @schneems says: > You need your pool to at least be as large as your puma thread > count.
🎉 |
https://devcenter.heroku.com/changelog-items/594