Modification and rollback methodology for a set of objects and their state
In a system I am writing, I have the concept of package and service objects.
A package is a container for a collection of services, and has an intrinsic set of configurable restrictions. These restrictions include:
- Which types of service are supported
- The number of services that can be allocated to the package
- The properties that need to be set to specific values within said services
There is a need to be able to upgrade and downgrade between compatible packages. By doing so, the services within the package need to be transferred, modified and potentially created or deleted to meet the constraints of the new package.
This needs to be done before any money is taken to ensure that certain unique resources are allocated to the services (and ring-fenced).
The problem comes if payment fails and the upgrade is cancelled - how do we rollback the modifications and return to the previous state?
The following (non-exhaustive) list of issues could arise:
- By deleting services that are no longer compatible with the new package, unique constraints could be released which are then used by other packages (in other accounts etc.) stopping rollback being possible
- Services that are deleted are difficult to restore with references intact
- If services aren't deleted, they continue to consume unique constraints that might need to be used by other similar services
The way this is handled at the moment is through a package-specific set of steps that store objects out of the way (rather than deleting them), and hold a list of steps to restore state back in the event of rollback. However, this is done on a per-case basis, is error-prone and feels clunky.
I开发者_高级运维 was wondering if any of you had encountered anything similar and knew of a pattern or methodology that could be employed here. Basically we need to be able to update the state of a set of objects, commit the changes, but have the option to rollback to a previous version. NB: Within the system the state of objects can be serialised and stored.
Any "I wouldn't do it like that!" comments gratefully received with alternatives.
Here is an example:
Before upgrade:
After upgrade:
Done something similar, but, very quickly.
In order to perform an "undo" / "rollback", you need to do some things:
[1] To store / register / serialize the value of the given objects ("Package" and "Service" (s) ), before performing the operation.
If the operation succedes, that info could be discarted, or just stored as historical data. Otherwise, use it to return the objects to the previous state.
You may also want to register the new changes.
[2] You have to register a menu or collection of operations that can be done by your app, and eventually rollback.
+----------------+ +------------------+ |................| |..................| |................| |..................| |.......App......|/\ |.....Operation....| |................| ----------|..................| |................|\/ |..................| +----------------+ 1 * +------------------+
For example, if instead of the "package-and-services" application, you where doing a Paint program.
In your application, you'll have a collection of actions or operations, and one of that operations is the "Paint filled square".
[3] Each time you execute one of those operations, even, if duplicated, you have a register or log of each operation that can be done, or rollback.
+----------------+ +------------------+ |................| |..................| |................| |..................|/\ 1 |.......App......|/\ |....Operation.....| --------+ |................| ----------|..................|\/ | |................|\/ |..................| | +----------------+ 1 * +------------------+ | /\ | \/ | | +------------------+ | 1 | |..................| | +--------------------|..................| | * |.......Log........|----------+ |..................| * (The same operation can be |..................| registered in the log, +------------------+ several times)
When you execute you Paint app., you use the "paint filled squared", several times.
[4] You need, in your list a opposite operation, that restores the matching one.
+----------------+ +------------------+ |................| |..................|-------+ 1 |................| |..................| | |.......App......|/\ |.....Operation....| | |................| ----------|..................|-------+ 1 |................|\/ |..................| +----------------+ 1 * +------------------+
Using the previous Paint app. example, you should have an "restore filled squared" operation, that leaves the area, as before the user painted the filled squared.
Don't care how its done, care about that there should be a matching one.
[5] The matching opposite operation must be registered in the log, also.
精彩评论