Pete Hamilton

Scaling Heroku by Time of Day

Heroku is brilliant. However, I manage a rails application which has grown much larger recently. It’s a bespoke company-specific application so it’s only used during working hours. There are therefore long periods of time (at night, over the weekend) where I’m paying for dynos which simply aren’t going to get used.

All dynos in your application that are scaled above 0 will accrue usage–regardless of whether they’re actually receiving or processing requests

Adept Scale offers a solution which automatically scales but I know when my load is high and low, also it’s fairly consistent within working hours.

For fun, I decided to see if I could scale my heroku dynos by time period. Turns out it’s really easy.


Note: I use heroku’s scheduler combined with rake tasks below, but this could easily be done with scheduled jobs. If you have any trouble, comment and I’ll do my best to help you out.

Add the heroku-api gem

gem 'heroku-api'

Decide on limits and set them in your Heroku config

For a simple small application you might have something like:

heroku config:set HEROKU_WEB_HIGH=5
heroku config:set HEROKU_WEB_LOW=1
heroku config:set HEROKU_WORKER_HIGH=3
heroku config:set HEROKU_WORKER_LOW=1

Add rake tasks for scaling up/down

I also add logic to prevent scaling up if it’s the weekend

task :scale_up => :environment do
  return if Date.today.saturday? || Date.today.sunday?

  heroku = Heroku::API.new
  heroku.post_ps_scale(YOUR_APP_NAME, 'web', ENV['HEROKU_WEB_HIGH'])
  heroku.post_ps_scale(YOUR_APP_NAME, 'worker', ENV['HEROKU_WORKER_HIGH'])
end

task :scale_down => :environment do
  heroku = Heroku::API.new
  heroku.post_ps_scale(YOUR_APP_NAME, 'web', ENV['HEROKU_WEB_LOW'])
  heroku.post_ps_scale(YOUR_APP_NAME, 'worker', ENV['HEROKU_WORKER_LOW'])
end

Deploy

git push heroku master

Add the Heroku Scheduler addon

heroku addons:add scheduler

Add Heroku Scheduler Tasks

Visit the heroku scheduler dashboard and add your rake tasks.

  • Add rake scale_up in the morning e.g. 8:00 am
  • Add rake scale_up in the evening e.g. 7:00 pm

Extensions

You could add gems like holidays to run in your rake tasks and help prevent scaling up on public holidays as well as just the weekends.

You could also add more scheduled tasks throughout the day, or just have one task which runs more frequently and performs the logic of scaling up/down within it. It’s up to you!

What could we save?

  • Assume the app is only used 8:00am - 7:00pm
  • Assume high = 20 paid web dynos, 10 paid worker dynos.
  • Assume low = 0 paid web dynos, 0 paid worker dynos (one free web dyno)
  • In the UK, there are 253 working days in 2014
  • Dynos are $0.05/h, prorated to the second
Before: $0.05 * 30 dynos * 24 hours * 365 days = $13140
After: $0.05 * 30 dynos * 13 hours * 253 days = $4993.50
Savings: ~ $8000 a year!

Per Dyno Time: 8760 vs 3298 hours per year. Quite a difference.

In fact, I could more than double my number of operating dynos using this method and still save money.

Disclaimer

There are a number of cases where obviously this simply isn’t logical, for example if your application is used in multiple timezones or needs to handle unexpected traffic spikes. However if you know your requirements and they match mine, this could be pretty helpful at helping you keep your application usable without breaking the bank.