One of the many benefits of the Heroku platform is its ease of integration into modern Continuous Integration (CI) and Continuous Delivery (CD) workflows. Heroku’s built-in CI makes it incredibly easy to keep all your code running in a single platform, without the need to rely on third party tools and without the need to configure and maintain them separately.
It’s also extremely affordable, as Heroku charges just $10 per month to host your CI pipeline and the actual Heroku usage charges on top of that are generally trivial for highly tuned test suites.
With Heroku CI configured, a staging environment can be deployed automatically with each merge to master and each successful pass of the test suite. Promotions from staging to production happen via Heroku Pipelines. With a simple click in the web UI, or via the Heroku command line interface, an instant deploy to production can take place without the need to recompile assets, rerun the tests, or regenerate the dyno slug, Heroku’s containerization process. The environment variables are simply changed to the production values and traffic routes to the new code.
Attentive Heroku users may notice a slight hesitation after promoting or restarting dynos, as traffic is held at the load balancer after the old dynos are shut down and must await the start of the new dynos.
That leads us to one of the best kept secrets of the Heroku Continuous Delivery pipeline: Preboot, a feature which boots up new dynos before shutting down the old ones. Enabling preboot is simple:
$ heroku features:enable -a your-app-name preboot
Enabling preboot for your-app-name... done
After enabling, you’ll notice on your next pipeline promotion that you aren’t seeing your new code right away. That’s because Heroku waits 3 minutes to start routing traffic away from your old dynos and onto your new ones. If the hesitation of that dyno reboot is bothersome to you, you may find the trade off of a slight delay at deploy time to be worth it. For our highest-volume sites, we found preboot to be a valuable feature.
One caveat is that of database migrations. When you promote the pipeline, the Heroku release phase is executed. This is typically the best place and time to run database migrations, so a standard Rails app on Heroku might have bundle exec rake db:migrate
in it’s Procfile release phase.
However, with preboot, 3 minutes will pass before the new code is served and after the migrations have executed. That means, the old code will still be running against the new database schema. For many types of migrations, such as adding additional tables and columns, this will have no impact. But if you rename a column, this could have adverse affects. For that reason, it’s best to be careful about your migrations, always to write zero downtime migrations, and as a last resort, disable preboot before deploying disruptive migrations.
Overall, we’ve found the trade off of 3 extra minutes of wait time to be well worth it to avoid that unsightly hesitation at deploy time. If you’re serving a high traffic website on Heroku, consider trying out Preboot to reduce the disruptions in your deployment process.