What should you consider when rolling back? Read on for the various options.
This section describes actions you would take to handle issues that prevent you from otherwise proceeding (or planning ahead for such cases). The main use cases:
The following are various paradigms to follow to handle or plan for these situations. We list these out in priority order:
You may ultimately need to consider all options; e.g. you may always write backwards-compatible changes, but you may still need to roll forward in some cases.
More details on each section:
(Only applicable for UC2)
If it were easy to put your database back into its previous state, then great. Most often, it is not the case, as tables are stateful objects. For example, adding and then removing table columns would mean physically changing all the rows in the database, which can be an expensive operation. Not to mention that such a rollback operation should also be tested.
What is an easier way to roll back your DB changes then? How about…not rolling them back at all?
Making your DB schema changes backwards-compatible to your code would help in this regard. The DB migration can only be done once and not worried about again, as this is a relatively more expensive operation than app binary updates.
Some teams have taken it as far as releasing DB code changes far in advance of application code changes as to prove backwards compatibility.
Some general rules on what changes are/aren’t backwards-compatible:
More notes here on Martin Fowler’s page (search for references to “destructive chagnes”)
However, you may not be able to escape such non-backwards-compatible changes; or you may choose not choose for the overhead of backwards-compatible changes. Then choose from the next possible options.
Instead of preparing to rollback, you may instead choose to release a new patch version to fix the issue with your release. The patch can be either in your application code or in your database code.
A risk here is that you do not have your changes pre-planned, and so if an issue comes up, you would need to come up w/ a solution on the fly. However, depending on your application characteristics (well-tested, nimble for making and deploying changes, able to cope with the bug for long enough), this can be suitable for you as this saves the overhead of planning out backwards-compatible changes or rollback scripts.
To roll forward, treat this change much as you would treat a patch release, e.g.
… For executing the deploy, you have options:
Ultimately, the purest form of rollback would be to take a raw copy of the DB before doing the deployment, and then switching back to it if the code also needs to get rolled back.
Some DBMSs (e.g. Sybase ASE) do provide such tooling for this (e.g. dbdump and restore). Thus, you can resort to this mode of rollback if you choose (likely, your DBAs should be taking backups of your DB anyway). As the Obevo audit table is also physically on your target DB, the state of the audit table will also get rolled back to where it should be.
The main negative with this approach is if your DB is huge, then this process will take a while to run and requires a lot of disk storage in your infrastructure. Hence, most teams will not go with this for practical reasons, but certainly if you have the resources and time for it, this is an acceptable option.
Obevo supports rollback by simply allowing developers to point to their old DB package and re-deploy w/ the -rollback flag attached
For example:
# do the deployment of version 1 $OBEVO_HOME/bin/deploy.bat DEPLOY -env prod -sourcePath /home/myuser/mypackage/1.0.0/db # do the deployment of version 2 (which contains rollback scripts if needed) $OBEVO_HOME/bin/deploy.bat DEPLOY -env prod -sourcePath /home/myuser/mypackage/2.0.0/db # let's say that goes bad; we'll rollback to version 1 by deploying it w/ the -rollback tag $OBEVO_HOME/bin/deploy.bat DEPLOY -env prod -sourcePath /home/myuser/mypackage/1.0.0/db -rollback
In the example above, the changes in version 2 need to include the rollback scripts.
In terms of what roll providing the scripts:
//// CHANGE name=chng-from-1.0.0 CREATE TABLE TABLE_A ( A_ID INT NOT NULL, B_ID INT NOT NULL, STRING_FIELD VARCHAR(30) NULL, TIMESTAMP_FIELD TIMESTAMP NULL, PRIMARY KEY (A_ID) ) GO //// CHANGE name=chng-from-2.0.0 ALTER TABLE TABLE_A ADD COLUMN C_ID INT NULL GO // ROLLBACK ALTER TABLE TABLE_A DROP COLUMN C_ID GO
In case you are interested in the technical details behind this: {panel}First, let’s review how regular deployments are done and changes detect (see Design Walkthrough doc)
Now for rollback:
Note that if you execute this rollback command, it will still ultimately remain in your source code to be deployed in subsequent releases and in the UAT environments that you deployed to. If you want to remove this change entirely (i.e. not let it come back in the next release), see the section below for “(Special Case) Undoing a table/incremental change permanently in non-prod or after rollback”
This involves creating a backup of the table during your deployment (e.g. MY_TABLE_BAK20141017), copying the data over, and proceeding w/ the deployment.
Pros:
While certainly we can add tooling around this to support this use case, most teams can get by using the others listed earlier. Hence, we haven’t built anything to support this paradigm as of yet
The above scenarios are what you should do if you are rolling back a change in production.
However, in non-prod (e.g. qa/uat), you still have cases where you want to undo a change you had applied during your current version. For undoing table changes, this would mean adding another //// CHANGE entry (assuming you can’t just wipe away and clean your db)
But if you are in qa/uat, you may have a lot of these changes building up if you have a lot of corrections. What if you want to be able to undo the change in uat and be able to delete the change entry in your file too? (As discussed a few times earlier, you cannot simply delete a //// CHANGE entry as the tool catches that as a validation error)
To do that, you can add the ROLLBACK-IF-ALREADY-DEPLOYED subsection to your change, e.g.
//// CHANGE name=chng-from-1.0.0 CREATE TABLE TABLE_A ( A_ID INT NOT NULL, B_ID INT NOT NULL, STRING_FIELD VARCHAR(30) NULL, TIMESTAMP_FIELD TIMESTAMP NULL, PRIMARY KEY (A_ID) ) GO //// CHANGE name=uat-change ALTER TABLE TABLE_A ADD COLUMN C_ID INT NULL GO // ROLLBACK-IF-ALREADY-DEPLOYED ALTER TABLE TABLE_A DROP COLUMN C_ID GO
The way this will work: