-
1. Re: compensation
tom.baeyens Apr 14, 2006 4:59 AM (in response to tom.baeyens)compensation is not yet implemented, but we know how we want it to look like:
compensation should be based on the logs. logs can have pointers to nodes and actions.
logs, actions and nodes should be able to implement an Compensatable interface.
compensation should then be based on reverse playing the logs. compensation should be based on a date. all compensateble logs between now and the given date should be iterated in reverse and the compensate method should be invoked. logs that have references to compensatable nodes or actions can delegate the compensation behaviour to the nodes or actions.
this way, you can think of adding a kind of user-specific compensation inside of the process logs. e.g. for updates done to your domain model.
but be warned. compensation is tricky business. transactions are invented to preserve ACID properties. compensation cannot give those guarantees so you have to know what you're doing. -
2. Re: compensation
meltem.yesiltas Apr 17, 2006 9:13 AM (in response to tom.baeyens)I will explain our requirement with a sample. Think of an EFT process with some approval steps. Before the approval phase, we block required amount of money from the customer account balance. Then if the EFT is rejected or something goes wrong (e.g. task timeout), then we have to unblock the balance and finish the process.
So, for now, what we need is finishing the process with compensation, rather than going back some state in time. But I will try to cover both.
Based on your explanation, the following is what we plan to do. Note that the source code is not mature nor tested, it is just to show the idea.
1. Create an interfaceCompensatable
with one method:public boolean compensate(ExecutionContext context)
2. Create a base action class calledCompensatableAction
.public class CompensatableAction extends Action implements Compensatable { protected String compensateNodeName = null; protected String compensateActionName = null; public boolean compensate(ExecutionContext executionContext){ // Action has the priority, if it is not specified, then we look node. if(compensateActionName != null && !compensateActionName.equals("")){ Action compensateAction = this.getProcessDefinition().getAction(compensateActionName); return true; } if(compensateNodeName != null && !compensateNodeName.equals("")){ Node compensateNode = this.getProcessDefinition().getNode(compensateNodeName); compensateNode.enter(executionContext); return true; } } public void read(Element serviceExecutorElement, JpdlXmlReader jpdlReader) { super.read(serviceExecutorElement, jpdlReader); // Only one of this attributes must be specified. compensateNodeName = serviceExecutorElement.attributeValue("compensate-node"); compensateActionName = serviceExecutorElement.attributeValue("compensate-action"); } }
Note that, also new node types can implement Compensatable interface. But here I take actions as sample.
3. Create our custom actions extending CompensatableAction. The process definition may look like below (or compensate-action can be specified instead of node)<myAction ..... compensate-node = "someFlyingNode"> </myAction> <node name ="someFlyingNode"> <!--this node will have no entering or leaving transitions--> </node>
4. Add a new method to ProcessInstance class: compansate(Date toTime)
This method will search the logs for all compensatable actions and nodes that are executed, call the compansate methods of them.
If a date parameter is specified, then reverse play will continue till that date, and at the end, process token will be on the node that was active on that date and context also will be rewind in each step. If no date is specified, then all executed nodes and actions will be traversed until the start state.
5. Create a generic action to call the compansate method of the process instance when necessary (for example when a timeout, reject or cancel occurs)<end-state name="reject"> <event type="node-enter"> <compansate date="......"/> </event> </end-state>
I am not sure how the engine will behave in this scenario. In the end state we rewind to the begining, and then expect the process to finish??? I dont know whether it works or not ? -
3. Re: compensation
meltem.yesiltas Apr 17, 2006 9:27 AM (in response to tom.baeyens)A forgotten detail about the forth item:
ProcessInstance::compensate method will stop to call compensatable nodes and actions if any of them return false from compensate method, but it should continue to rewind the context and token.
This is similar to event comsuming in Java. When compensating a node/action, it can tell the engine not to run compensation anymore.