This is a topic I’ve wanted to discuss for a long time. This post is to show you how to use a new component I’ve made called jbpm-rollback-api, a configurable module that allows you to rollback persistent jBPM process instances to a previous step. It makes it possible by just adding an environment variable, a process event listener and an extra class to the jBPM persistence unit. I’ll discuss it in as much detail as possible in Plugtree’s next Public Training in London, I invite you to register
When running process instances, especially during the first runs in a new BPM based project, you might get to a point where you wished you had done something different along the steps of your business process (maybe specifying a different value for a variable, or you end up in a path you didn’t wish in the first place. If you can’t change that aspect of the process instance, you need to drop it altogether. This isn’t an issue when running from a JUnit test case, but if you find this issue in a running system, you might not want to drop the process instance and start again, specially when it involves other people’s work. The possibility of rollbacking the tasks of a process allows you to get to a previous state of the process instance without having to start over again.
The whole idea spins around the way the process instances are persisted today in the database. Here’s a nice explanation of the database persistence if you wish to go into detail about it. In short, there is a small blob of data marshalled into each ProcessInstance row in the database. Since it is overwritten every time the process instance changes, the rollback module takes a copy of that blob and stores it aside to have it available after the process changes. It can’t just copy it every time it pleases when it is inside a database transacted operation, so it does it whenever the session reaches a safe state (that is, after the transaction is finished and the session method is ready to return). And it can’t just do it for all live process instances, that would be too expensive performance-wise. So it does it only for the process that changed during the last transaction.
Overall the configuration looks like this:
The way it works is by four simple components:
- ProcessSnapshotLogger: This class acts as two things:
- A process event listener to monitor for any process instance changes within a persistent session. If a process instance changes, we mark it as a candidate to persist a snapshot after the knowledge session transaction is done. Also if a process instance is completed, we mark the process snapshots of that instance for deletion to keep the database runtime at a steady size.
- It also works as an interceptor to wait for all safe states in a persistent session, to persist any changed process instances. The interceptor is added as a step every time a command of the command based knowledge session finishes executing.
- ProcessSnapshot: A database entity designed to store the full blob representation of a process instance every time it changes, to be able to reload it on demand afterwards.
- ProcessSnapshotAcceptor: Taking snapshots of process instances can affect performance, so this class provides a very simple interface to configure what process instances to monitor for rollback, omitting by default. You have a few implementations available that allow you to select all instances of a given process definition ID, all the instances, or you can implement your own by implementing the method boolean accept(String processId, long processInstanceId).
- ProcessRollback: A utility class to query for old snapshots of a process instance and to paste them on top of the preexisting process instance. You can use the goBack(KieSession ksession, long processInstanceId) static method to go back one step, or the overridden static method goBack(KieSession ksession, long processInstanceId, int numberOfSteps) to go back as many steps as you like
Internally, the rollback recreates the old process instance and reactivates any nodes that were alive at the moment of the snapshot. At the moment (and in this form) you don’t send any signals to external systems that steps taken in the process need to be rolled back. However, this would be a next step for this module; by creating a RollbackableWorkItemHandler interface with a rollbackWorkItem(WorkItem item, WorkItemManager manager) method that people could implement, the rollback could go one step at a time and notify any external systems about a rollback being effected. This is one of the many subjects we would love to discuss and teach about:
We at Plugtree are organizing a Public Training in London on October 21st to 25th at N 1 Poultry. We’ll cover Drools 5, 6, and jBPM 5 and 6 with as much detail as possible. We’ll introduce both the BPM and AI theory, as well as all technical specifications for the different components, in order to take the most advantage of Drools and jBPM. Here’s an overall agenda:
- Day 1: Introduction to all components, for technical and non-technical folks alike
- Days 2 and 3: Focus on Drools components, both versions 5 and 6, from theory to practice in as much detail as possible. We’ll also cover rule writing in most formats and best practices
- Days 4 and 5: Focus on jBPM components, both versions 5 and 6, from theory to practice in as much detail as possible. We’ll also cover BPMN2 writing in as much detail as possible.
You can click here to register. Take advantage of the early bird pricing!
If you wish to start downloading and playing with the code discussed here, you can download it from here