In the following exemple extracted from bernd ruecker blog, i can have an Order with Items from multi Supplier, so the “Ship goods” service will be a multi-instance one (by Supplier) and i have a “Received Task” when the micro service (Supplier) finish the shipping. When error occur in the Supplier micro service, the received task is in error and a compensation must be done for all Supplier.
The sub process named “Second step” is a multi instance one (loop cardinality = 5), with cancellation and compensation.
When a cancellation is throw, i’m expected to see compensation for all completed instances (of the sub process), but i only see compensation for the instance throwing the cancellation.
According to the documentation:
Note: In case a cancel boundary event is placed on a transaction subprocess with multi instance characteristics, if one instance triggers cancellation, the boundary event cancels all instances.
The documentation tell nothing about compensation for other completed instances. How to do it ? Why camunda don’t compensate all completed instances ? It’s a missing feature, a bug or a incomprehension of myself ?
To me - this makes a lot of sense. The instance that triggers the compensation should be the only one that is compensated. the fact the this compensation is triggered by an interrupting cancel event happens to cancel the remaining instances is a function of the boundary event rather than the compensation itself.
If your goal is the compensate all instances when if a single instance triggers a compensation there might be a better way of doing it. I’ll see what i can come up with.
If your goal is the compensate all instances when if a single instance triggers a compensation there might be a better way of doing it. I’ll see what i can come up with.
My goal is at best to compensate only completed instance in the case of a multi transaction sub process.
I wondering if the signal event will be caught by other process instances ? If yes, it’s a big deal :D. I only want the multi instance of the current processes to be compensate. Not for all process instances.
In your example, if before the sub process we add a service task with compensation, and the sub process failed, signal is launch, all multi instance are compensate but the task before will not be ? Can you confirm ?
It will only activate compensation tasks within the scope of the sub process. If you had and another task before the sub process it would not be triggered.
Can we catch the signal outside the sub process and compensate the first task. Or this approch is restricted to sub process. If it is, is not the right way for us
(first step) => log ok
(second step) => log ok n°0
(back-end | ShipGoodAdapter) call (Supplier) micro service n° 0
(second step) => log ok n°1
(back-end | ShipGoodAdapter) call (Supplier) micro service n° 1
(second step) => log ok n°2
(back-end | ShipGoodAdapter) call (Supplier) micro service n° 2
(second step) => log ok n°3
(back-end | ShipGoodAdapter) call (Supplier) micro service n° 3
(second step) => log ok n°4
(back-end | ShipGoodAdapter) call (Supplier) micro service n° 4
(second step) => after received task with success:true for n°0
(second step) => after received task with success:true for n°1
(second step) => after received task with success:true for n°2
-------------------
(back-end) send step 2 ship good compensation !!!!
-------------------
(second step) => after received task with success:false for n°3
(second step) => event sub process compensation from signal n°4
(second step) => log compensation n°4
before all compensation
(first step) => log compensation
(second step) => event sub process compensation from globall compensation n°null
(second step) => event sub process compensation from globall compensation n°null
(second step) => log compensation n°null
(second step) => ship compensation n°null
(second step) => log compensation n°null
(second step) => ship compensation n°null
(second step) => event sub process compensation from globall compensation n°null
(second step) => log compensation n°null
(second step) => ship compensation n°null
(second step) => event sub process compensation from globall compensation n°null
(second step) => log compensation n°null
(second step) => ship compensation n°null
(second step) => event sub process compensation from globall compensation n°null
(second step) => log compensation n°null
(second step) => ship compensation n°null
after all compensation
Signal occur for the item n°3 of the sub process (no compensation is launched) but compensation only for n°4 that is not yet finished. Items n°1, 2, 3 are completed and no compensate . Not what i want but it’s understandable.
Plus, the non interrupting signal boundary event is not fired, compensate is fired by the the last compensation of the process, between the log “before all compensation” and “before all compensation”. I’m not sure about understanding the expected behavior with the non interrupting signal boundary event on a multi-instance subprocess with event sub process and compensation…
Plus the compensation order is strange, the first step run before second step (sub process). From what I understand from the documentation, the compensation must be done in the reverse order. Why all the items of the second step are not compensate before the first one ?
I have the project base on the camunda-unittest project, if you need it @Niall .
public class SmartShipGoodService extends PublishSubscribeAdapter {
private static Integer count = 0;
public void execute(final ActivityExecution context) throws Exception {
addMessageSubscription(context, "Message_shipping");
System.out.println("(back-end | ShipGoodAdapter) call (Supplier) micro service n° "+context.getVariable("loopCounter"));
}
}
public class PublishSubscribeAdapter extends AbstractBpmnActivityBehavior {
public void signal(ActivityExecution execution, String signalName, Object signalData) throws Exception {
leave(execution);
}
protected void addMessageSubscription(final ActivityExecution context, String eventName) {
ExecutionEntity executionEntity = (ExecutionEntity)context;
EventSubscriptionEntity eventSubscriptionEntity = new EventSubscriptionEntity(executionEntity, EventType.MESSAGE);
eventSubscriptionEntity.setEventName(eventName);
eventSubscriptionEntity.setActivity(executionEntity.getActivity());
eventSubscriptionEntity.insert();
}
}
@Test
@Deployment(resources = {"testProcess4.bpmn"})
public void shouldExecuteProcess4() {
ProcessInstance processInstance = runtimeService().startProcessInstanceByKey("testProcess4");
List<Execution> messagesShipping = getExecutions(processInstance); // cardinality is 5 for the subprocess
for (int i = 0; i < messagesShipping.size(); i++) {
Map<String, Object> variables = new HashMap<String, Object>();
if (i == 3) { // set i == 30 to avoid sub process signal and arrive to the global compensation
System.out.println("-------------------");
System.out.println("(back-end) send step 2 ship good compensation !!!!");
System.out.println("-------------------");
variables.put("success", false);
} else {
variables.put("success", true);
}
// compensate received message added programmatically be SmartShipGoodService
// some message sending can failed due to sub process signal launch and the compensation already append
runtimeService().messageEventReceived("Message_shipping", messagesShipping.get(i).getId(), variables);
}
}
private List<Execution> getExecutions(ProcessInstance processInstance) {
return executionQuery().processInstanceId(processInstance.getId()).messageEventSubscriptionName("Message_shipping").list();
}
When all is good in the subprocess and i want compensate later, with the last step, outside of the subprocess. Imagine the second step is a call to one micro service, but i have 5 like that in my real case. Also, i realized that i need to order myself the compensation inside the subprocess with an event subprocess if not, the compensation was not well ordered.