We started out with two apps.
- foo-staging
- foo-production
Our CI would run tests, then deploy to staging, run smoke tests and then run to production and run smoke tests.
This took about 22-25 min.
Our tests take around 3-3.5 minute to run. The rest of that was waiting for deploys to finish.
I added a third application:
- foo-prepare
Using these steps:
- Added the buildpacks we use and set the parts of the config we use within buildpacks (e.g. things like imagemagick version). I configured it as production and made sure our staging app could run with assets built for production.
- Added heroku metadata
heroku labs:enable runtime-dyno-metadata -a foo-prepare
so we could access the deployed commit later on. - Pushed to the new app and made sure the deploy worked.
- Scaled down the web dyno to 0 as we won't use it.
- Set up a pipeline for the three apps.
heroku pipelines:create foo --app foo-prepare
(as dev)heroku pipelines:add foo --app foo-staging
(as staging)heroku pipelines:add foo --app foo-staging
(as production)
I then added a parallel job in CI that would push the commit to foo-prepare
while tests ran.
I changed the deploy step to something like this:
function _deploy_to_heroku {
heroku git:remote --remote prepare --app foo-prepare > /dev/null
# First try to use the deploy we've prepared while running tests
if [ "$GIT_COMMIT" == "$(heroku config:get HEROKU_SLUG_COMMIT -r prepare)" ]; then
echo "Promoting slug based on $GIT_COMMIT from foo-prepare to $app_name"
heroku pipelines:promote --app foo-prepare --to $app_name
else
# deploy normally...
fi
}
And that's it.
Using this our commit-to-production time is now 10 minutes. A bit more than twice as fast as before.