Advanced Heroku Settings For Rails
Tags: rails, heroku, devops
Published: 2022-02-16 18:51:33

Deploying your [Rails](https://rubyonrails.org) app to [Heroku](https://heroku.com) is generally straight forward, however there's a lot of additional configuration needed to make sure things scalable and memory efficient. The following are some tips and recommendations on setting up your Rails app on Heroku.

Note, before setting these environment variables or adding the buildpacks, make sure you’ve first deployed your Rails app to Heroku. Adding these variables or buildpacks before can mess up the initial setup process.

---

### Jemalloc Buildpack

> jemalloc is a general purpose malloc implementation that works to avoid memory fragmentation in multithreaded applications. This buildpack makes it easy to install and use jemalloc on Heroku and compatible platforms.

You can add the `jemalloc` buildpack by running the following.
```shell
heroku buildpacks:add --index 1 https://github.com/gaffneyc/heroku-buildpack-jemalloc.git
```

Next you'll need to set the `JEMALLOC_ENABLED` environment variable on Heroku.
```shell
heroku config:set JEMALLOC_ENABLED=true
```

More information at [elements.heroku.com/buildpacks/gaffneyc/heroku-buildpack-jemalloc](https://elements.heroku.com/buildpacks/gaffneyc/heroku-buildpack-jemalloc).

---

### Postgres Bouncer Buildpack

> This is a Heroku buildpack that allows one to run pgbouncer in a dyno alongside application code. The primary use of this buildpack is to allow for transaction pooling of PostgreSQL database connections among multiple workers in a dyno.

Add the `heroku-buildpack-pgbouncer` buildpack by running.
```shell
heroku buildpacks:add https://github.com/heroku/heroku-buildpack-pgbouncer
```

Next, either add or update your `Procfile`, the below is assuming you are using Sidekiq.
```shell
web: bin/start-pgbouncer-stunnel bundle exec puma -C config/puma.rb
worker: bundle exec sidekiq -C config/sidekiq.yml
```

_Important_, in your `config/database.yml` ensure the following flags are set in your `production` environment.
```shell
advisory_locks: false
prepared_statements: false
```

More information at [elements.heroku.com/buildpacks/heroku/heroku-buildpack-pgbouncer](https://elements.heroku.com/buildpacks/heroku/heroku-buildpack-pgbouncer).

--- 

### Set Rails Master Key
If you are using `config/credentials.yml.enc`, you'll need to set the `RAILS_MASTER_KEY` environment variable.

```shell
heroku config:set RAILS_MASTER_KEY=`cat config/master.key`
```

---

### Change Service Timeout
You can specify request timeout by setting the `RACK_TIMEOUT_SERVICE_TIMEOUT` environment variable.

```shell
heroku config:set RACK_TIMEOUT_SERVICE_TIMEOUT=20
```

More information at [devcenter.heroku.com/articles/deploying-rails-applications-with-the-puma-web-server#timeout](https://devcenter.heroku.com/articles/deploying-rails-applications-with-the-puma-web-server#timeout).

---

### Set Sensible Defaults
> If a Ruby application has the configuration variable SENSIBLE_DEFAULTS set, then the configuration variable WEB_CONCURRENCY will be defaulted to a value based on the dyno size.

```shell
heroku config:set SENSIBLE_DEFAULTS=enabled
```

More information at [devcenter.heroku.com/changelog-items/618](https://devcenter.heroku.com/changelog-items/618).

---

### Enable Preboot
> Preboot changes the standard dyno start behavior for web dynos. Instead of stopping the existing set of web dynos before starting the new ones, preboot ensures that the new web dynos are started (and receive traffic) before the existing ones are terminated. This can contribute to zero downtime deployments.

You can [enable preboot functionality](https://devcenter.heroku.com/articles/preboot#enabling-and-disabling-preboot) by running the following.

```shell
heroku features:enable preboot
```

More information at [devcenter.heroku.com/articles/preboot](https://devcenter.heroku.com/articles/preboot).

---

### Enable Runtime Heroku Metrics

>To provide additional insights into memory health we offer optional language-specific runtime metrics. JVM, Go (public beta), Node.js (public beta), and Ruby (public beta) are currently supported.

```shell
heroku labs:enable "runtime-heroku-metrics"
```

More information at [devcenter.heroku.com/articles/language-runtime-metrics](https://devcenter.heroku.com/articles/language-runtime-metrics).

---

### Enable Ruby Language Metrics
> To provide more visibility into the Ruby runtime, the Ruby language metrics feature surfaces additional language-specific time series metrics within Application Metrics. Ruby metrics include free and allocated heap object counts and number of free memory slots.

```shell
heroku labs:enable "ruby-language-metrics"
```

More information at [devcenter.heroku.com/articles/language-runtime-metrics-ruby](https://devcenter.heroku.com/articles/language-runtime-metrics-ruby).

---

### Set Ruby GC heap Growth Factor
> When it comes to memory utilization you can control how fast Ruby allocates memory by setting RUBY_GC_HEAP_GROWTH_FACTOR. This value is different for different versions of Ruby. To understand how it works it is helpful to first understand how Ruby uses memory.

```shell
heroku config:set RUBY_GC_HEAP_GROWTH_FACTOR=1.03
```

More information at [devcenter.heroku.com/articles/ruby-memory-use#gc-tuning](https://devcenter.heroku.com/articles/ruby-memory-use#gc-tuning).

---

### Rails Autoscale Add-on
[RailsAutoscale](https://railsautoscale.com) is one of the must have add-ons for Heroku. It lets you scale your web and worker dynos up and down based on queue time. So besides helping your application scale, it can also save you a lot or money.

More information at [elements.heroku.com/addons/rails-autoscale](https://elements.heroku.com/addons/rails-autoscale).

---

### Scout APM Add-on
[Scout APM](https://elements.heroku.com/addons/scout) is another must have add-on for Heroku. It helps find N+1 queries, slow database queries, memory bloat and more.

More information at [elements.heroku.com/addons/scout](https://elements.heroku.com/addons/scout).

---

### Choosing Your Dynos
I highly recommend you read [How many Heroku dynos do you need, and which size—An opinionated guide](https://railsautoscale.com/how-many-dynos/) from [railsautoscale.com](https://railsautoscale.com). [Adam](https://twitter.com/adamlogic) does a great job explaining and recommending different dyno types, as well as their ideal settings for scaling.

More information at [railsautoscale.com/how-many-dynos/](https://railsautoscale.com/how-many-dynos/).

---

### Heroku Commands
And finally some handy commands for Heroku.

- Server Deploy `git push heroku main`
- Server Logs `heroku logs --tail`
- Server Restart `heroku restart`
- Rails Console `heroku run rails console`
- Postgres Info `heroku pg:info`
- Postgres Diagnose `heroku pg:diagnose`
- Maintenance On `heroku maintenance:on`
- Maintenance Off `heroku maintenance:off`
- Database Drop `heroku pg:reset DATABASE`
- Database Migrate `heroku run rake db:migrate`
- Database Seed `heroku run rake db:seed`

---

Are there other Heroku settings or optimization you like to make? I'd love to hear from you in the comments!