Search code examples
rubypostgresqlherokusinatrasinatra-activerecord

"PG::ConnectionBad - could not connect to server: Connection refused" Sinatra server on Heroku


My Mad Libs program (code, Heroku app; earlier version on repl.it) runs fine in my Ubuntu VirtualBox, and for a few minutes after pushing the code to Heroku, it was actually working on Heroku, too. Then after maybe 15-30 minutes either I did something or something happened on the server, and ever since the app page says "Internal Server Error" and the relevant part of server logs read:

2018-04-14T02:03:45.717579+00:00 heroku[web.1]: Starting process with command `bundle exec ruby app.rb -p 7330`
2018-04-14T02:03:48.443468+00:00 app[web.1]: [2018-04-14 02:03:48] INFO  ruby 2.4.0 (2016-12-24) [x86_64-linux]
2018-04-14T02:03:48.443866+00:00 app[web.1]: == Sinatra (v2.0.1) has taken the stage on 7330 for production with backup from WEBrick
2018-04-14T02:03:48.443437+00:00 app[web.1]: [2018-04-14 02:03:48] INFO  WEBrick 1.3.1
2018-04-14T02:03:48.444166+00:00 app[web.1]: [2018-04-14 02:03:48] INFO  WEBrick::HTTPServer#start: pid=4 port=7330
2018-04-14T02:03:48.855874+00:00 heroku[web.1]: State changed from starting to up
2018-04-14T02:04:04.372745+00:00 heroku[router]: at=info method=GET path="/" host=youmadlibs.herokuapp.com request_id=118d681f-3402-44aa-9d04-75d930461195 fwd="74.135.49.116" dyno=web.1 connect=0ms service=20ms status=500 bytes=854 protocol=https
2018-04-14T02:04:04.368607+00:00 app[web.1]: 2018-04-14 02:04:04 - PG::ConnectionBad - could not connect to server: Connection refused
2018-04-14T02:04:04.368644+00:00 app[web.1]:    Is the server running on host "localhost" (127.0.0.1) and accepting
2018-04-14T02:04:04.368648+00:00 app[web.1]:    TCP/IP connections on port 5432?
2018-04-14T02:04:04.368651+00:00 app[web.1]: :
2018-04-14T02:04:04.368653+00:00 app[web.1]:    /app/vendor/bundle/ruby/2.4.0/gems/pg-1.0.0/lib/pg.rb:56:in `initialize'
2018-04-14T02:04:04.368654+00:00 app[web.1]:    /app/vendor/bundle/ruby/2.4.0/gems/pg-1.0.0/lib/pg.rb:56:in `new'
2018-04-14T02:04:04.368656+00:00 app[web.1]:    /app/vendor/bundle/ruby/2.4.0/gems/pg-1.0.0/lib/pg.rb:56:in `connect'
2018-04-14T02:04:04.368659+00:00 app[web.1]:    /app/vendor/bundle/ruby/2.4.0/gems/activerecord-5.2.0/lib/active_record/connection_adapters/postgresql_adapter.rb:684:in `connect'
etc.

The relevant lines seem to be:

PG::ConnectionBad - could not connect to server: Connection refused
Is the server running on host "localhost" (127.0.0.1) and accepting TCP/IP connections on port 5432?

I've tried a bunch of stuff, like restarting the server, reducing the dynos to 0 and then re-upping to 1, and running $ heroku run psql -h HEROKU_POSTGRESQL_SILVER_URL -U deploy youmadlibs . I read the Heroku documentation for connecting Ruby to databases, and for database.yml, it has host: localhost. I tried that (despite the fact that it had worked before with the setting I have below, which I took from a tutorial). I also tried a different set of database.yml settings from this tutorial. No dice! I read many answers here and elsewhere and can't figure it out. How can I get the database-server connection reestablished?

database.yml:

development:
  adapter: sqlite3
  database: db/madlibs.sqlite
  host: localhost
  pool: 5
  timeout: 5000

production:
  url: <%= ENV['DATABASE_URL'] %>
  adapter: postgresql
  database: mydb
  host: <%= ENV['DATABASE_HOST'] %>
  database: <%= ENV['DATABASE_NAME'] %>
  username: <%= ENV['DATABASE_USER'] %>
  password: <%= ENV['DATABASE_PASSWORD'] %>
  pool: 5
  timeout: 5000

.env:

DATABASE_URL=<...my database name...>

config/environment.rb:

configure :development do
  set :database, {adapter: "sqlite3", database: "db/madlibs.sqlite3"}
  set :show_exceptions, true
end

configure :production do
  db = URI.parse(ENV['DATABASE_URL'] || 'postgres://localhost/mydb')

  ActiveRecord::Base.establish_connection(
      :adapter  => db.scheme == 'postgres' ? 'postgresql' : db.scheme,
      :host     => db.host,
      :username => db.user,
      :password => db.password,
      :database => db.path[1..-1],
      :encoding => 'utf8'
  )
end

Gemfile:

source 'https://rubygems.org'
ruby '2.4.0'

gem 'sinatra', '2.0.1'
gem 'pg', '1.0.0'
gem 'activerecord', '5.2.0'
gem 'sinatra-activerecord', '2.0.13'
gem 'sinatra-flash', '0.3.0'                # Probably not nec.
gem 'sinatra-redirect-with-flash', '0.2.1'  # Probably not nec.
gem 'rake', '10.4.2'
gem 'rack', '2.0.3'
gem 'sass', '3.4.24'
gem 'json', '2.1.0'

group :development do
  gem 'sqlite3', '1.3.13'
  gem 'tux', '0.3.0'                        # Maybe unnec.
end

group :production do
end

The top of app.rb:

require 'sinatra'
require 'sinatra/activerecord'
require './config/environment'
enable :sessions

class Madlib < ActiveRecord::Base
end

Solution

  • You don't need the other lines if you have the db url, it can be a 1 liner, and also let postgres timeout it's default, no need to set it. You probably want a larger pool size in prod. Go to the postgres database you should have added to your app in Heroku. Click on the View Credentials button. Copy the data from there to your local .env file and also add .env to your .gitignore file because you don't want to commit your private credentials to your public repo.

    Then on heroku

    database.yml:
    
    development:
      adapter: sqlite3
      database: db/madlibs.sqlite
      host: localhost
      pool: 5
      timeout: 5000
    
    production: 
      adapter: postgresql
      encoding: unicode
      host: <%= ENV['DB_HOST'] %>
      username: <%= ENV['DB_USERNAME'] %>
      password: <%= ENV['DB_PASSWORD'] %>
      port: <%= ENV['DB_PORT'] %>
      database: <%= ENV['DB_NAME'] %>
      pool: 25
    

    Alternatively, you could just use 1 environment variable which concatenates all of this into a URI which would look something like

    #postgresql://username:[email protected]:1234/db
    #If you use this format you can use just a single environment variable somthinglike
    
    production: 
      adapter: postgresql
      encoding: unicode
      url: <%= ENV['DATABASE_URI'] %>
      pool: 25
    

    In either case you will need to set whatever environment variables you'll use in your database.yml file set in your Heroku dashboard at: https://dashboard.heroku.com/apps/yourappname/settings and click on Reveal Config Vars. This is where you will set the needed vars as this is where your app will load them from. Set either the vars in my first example, or a single one as in my 2nd example. Either way should work.

    Make sure you have the pg gem in your production group in Gemfile. And make sure you've set your environment variables on your heroku server.