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
- https://devcenter.heroku.com/articles/usage-and-billing#computing-usage
- https://devcenter.heroku.com/articles/usage-and-billing#cost
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.