Migrate on push with Heroku releases
I use Heroku for most of my hosting, and also use it a lot in my work at Rabid Technologies. Something I frequently run into is a migration not being run after a git push heroku master
, often causing an embarrasing application error page until someone can get to running heroku run rake db:migrate
.
Fortunately, Heroku supports release commands. These commands are run after each successful deployment, and also delay the restart of the dyno(s). This allows for any post-code-update steps to be taken before the application is updated for users.
Declaring release commands is very simple - a line simply needs to be added to the Procfile
stating which commands should be run upon release. For example, this is the line I use to run migrations:
# Procfile
# ...
# release: bundle exec rake db:migrate
Adding this to your Procfile will change your post-receive hook output from Heroku slightly, as it will now output the status of the release command:
remote: -----> Launching...
remote: ! Release command declared: this new release will not be available until the command succeeds.
remote: Released v160
remote: https://myapp.herokuapp.com/ deployed to Heroku
remote:
remote: Verifying deploy... done.
remote: Running release command....
remote:
remote: (0.6ms) SELECT pg_try_advisory_lock(7931432920140052365)
remote: (1.2ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
remote: ActiveRecord::InternalMetadata Load (0.7ms) SELECT "ar_internal_metadata".* FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = $1 LIMIT $2 [["key", "environment"], ["LIMIT", 1]]
remote: (0.7ms) BEGIN
remote: (0.5ms) COMMIT
remote: (0.9ms) SELECT pg_advisory_unlock(7931432920140052365)
remote: Waiting for release.... done.
I find that this functionality is particularly useful for continuous deployment setup, as it only requires git
to be installed to perform a Heroku deployment AND automatically run migrations. Without this functionality, it is slightly harder, as the deploy needs to happen in two steps - one to do the git push
, and then another to do the heroku run
. This process also requires the Heroku CLI to be installed and authenticated, which isn’t always the easiest thing in CI environments.