As we have shown in a previous blog post - dotmesh enables you to commit stateful container data, creating a history of snapshots.
That’s great as a backup system and audit trail, but when you roll back to commits to undo changes, that throws away the state since that commit. Branches are like copies of the datadot that have their own history of commits after their creation, without disturbing the original.
Imagine your stateful app is happily whirring away in production. Users are busily buying, sharing, and looking at the lovely ads. But you have a new release of the software to deploy, and it involves a complicated database migration because you’re changing your database schema to improve performance and let you add some cool new features over the next few months.
Your production database is complicated, and the migration is nontrivial, so the obvious way to test it is to take a dump of the production database and load it into your staging environment. Then you can perform the migration in staging and check everything works out, without having to risk breaking your live site if it doesn’t go so well.
Before dotmesh, this would involve taking a dump of the production database (hopefully, you have them anyway as part of your backup system!) and then performing the burdensome task of restoring that database dump into your production environment which, for a nontrivial database, would take a few hours. Also, if you have multiple databases (perhaps because your application is divided into microservices) then there’s a lot of manual work to get them all restored individually.
Doing it with datadots.
With that in place, bringing the production data into the staging environment is a simple matter of cloning the production data dot from the Hub into the staging environment:
$ dm clone hub myapp
This creates a local copy of the application state, and indeed, we could just start testing our migration on it without using branches. But this would mean that the history of the dot diverges from the ongoing process of scheduled commits in the production environment, and we wouldn’t be able to keep our local copy synchronised with production. We’re going to do all our experiments on branches, and keep the master history of the dot synchronised with production.
What we want to do is to branch away from the series of scheduled commits that form the “master branch” of the dot, so we can test our migration independently, committing after each stage - and then, later, re-run that test against a newer commit of production data:
First we create a branch called
$ dm switch myapp $ dm checkout -b v3-migration-test
Now we can run our application against that dot, and make commits to record each stage of the migration. If it goes wrong, we can roll back to an earlier stage and just re-run the stage that failed, rather than needing to redo the whole thing!
But when we iron out all the bugs in the migration process, which may
take days, we need to do one final test with the latest production
state. Thankfully, this is easy. Because we worked on a branch, the
master branch of the datadot has not diverged from production, so we
can update it from our latest backup commits:
$ dm pull
And then we can create a new branch from the latest master:
$ dm checkout master $ dm checkout -b v3-migration-test-2
We re-run the migration, and if everything still works perfectly, we’re good to go live!
But if not, don’t sweat. You can repeat the debugging process to get
it working again, and then make a
v3-migration-test-3 branch for a
final (final for real this time!!) test. Commits, branches, and
rollbacks make it easy to try experiments on your production data,
without interfering with production.
Because we kept our experiments on branches, we never need to clone the dot from production into staging again; we can make it track production automatically with scheduled pulls that only need to download the changes. Multiple teams can create their own branches to test migrations, or any other test that needs to use production data. Being dedicated branches, they won’t interfere with each other.