Zero Downtime Deploys with Entity Framework Migrations

At Moneybox, we've implemented a continuous delivery pipeline using TeamCity, Octopus Deploy and Azure WebApps. Taking this a bit further, by making use of the deployment slot functionality of Azure WebApps, we were able to implement one click, zero downtime deployments with minimal effort.

In summary, this works by deploying our app into a staging deployment slot, waiting for the app to start responding to ping requests and then swapping the staging slot with the production slot. The old production slot now becomes the staging slot and is kept warm (i.e able to respond to requests) in case a quick rollback is needed.

The normal practice for deploying database changes in a zero downtime manner is to ensure that they're always backwards compatible, allowing both the old and new versions of the app to run side by side. In essence this means that database additions should have default values (or be nullable), renames aren't allowed and database removals should first have the dependency removed from the application, said change released to production, followed by an additional release to remove the object from the database.

This is easy to understand in theory but translating it into practice is a little tricky when using Entity Framework Migrations to control database changes. By default, if EF detects that you're out of sync with the database, and even if this change is forward compatible, it will prevent your application from starting and return an error along the lines of the following:

The model backing the 'ExampleContext' context has changed since the database was created.

This feature is great in development as you're instantly aware if a migration has been added on master and needs applying to your local database. It does, however, prevent us from reaching the zero downtime panacea we were hoping for. The good news is that this feature can be disabled either via code or in a app setting in your config file. For us, the latter was the better approach as we could add it to the release transform of our application and have the best of both worlds, the feature enabled in development but disabled in production.

If you want to use the excerpt above in a normal config file (i.e not in a transform), simply remove dt:Transform="Insert" from the end of the setting.

This was the last piece of the puzzle in implementing a continuous delivery pipeline with Azure, Octopus Deploy and Entity Framework Migrations. I hope it's yours too.

Edit: 22/08/2016

Unfortunately this wasn't true as Entity Framework Migrations doesn't support dropping columns in a continuous delivery world. I've written up the issue here.

Edit: 01/02/2017

The last piece of the puzzle, dropping columns, can be found here.

Show Comments