In the execute()
, I make the actual call to the service, and I register for a callback when a reply is received.
When I receive the callback a bit later, I use runtimeService.signal(rpcSession.getExecutionId(), SendRpc.STATUS_OK, messageString, null);
so I end up in the signal()
code with an actual ActivityExecution
object.
In the signal()
method, I can then use the signalName to notify the engine if the result was OK, FAILED or has a TIMEOUT.
This is my actual signal()
code:
public void signal(ActivityExecution execution, String signalName, Object signalData) {
if (signalName.equals(STATUS_OK)) {
log.debug("[{}] Completing execution {} with variables {}", execution.getProcessInstanceId(), execution.getId(), signalData);
SpinJsonNode messageJson = Spin.JSON(signalData);
execution.setVariableLocal("response", messageJson);
leave(execution);
} else if (signalName.equals(STATUS_ERROR)) {
log.debug("[{}] Marking execution {} as errored with error {}", execution.getProcessInstanceId(), execution.getId(), signalData);
SpinJsonNode messageJson = Spin.JSON(signalData);
execution.setVariableLocal("response", messageJson);
try {
String errorCode = messageJson.jsonPath("$.errors[0].code").stringValue();
// We can't simply throw a BpmnError here, because when there is no Error Boundary Event defined, our
// error will be lost. We need to look ourselves for a Boundary Event that matches the error code.
// Setting enableExceptionsAfterUnhandledBpmnError doesn't seem to influence this, unfortunately.
// See https://forum.camunda.io/t/abstractbpmnactivitybehavior-thow-error-in-signal/8882
BoundaryEvent boundaryEvent = findBoundaryEventByErrorCode(execution, errorCode);
if (boundaryEvent != null) {
log.debug("[{}] Boundary event found for error code: {}", execution.getProcessInstanceId(), errorCode);
throw new BpmnError(errorCode, (String) signalData);
} else {
log.debug("[{}] No boundary event found for error code: {}. Creating incident.", execution.getProcessInstanceId(), errorCode);
execution.createIncident(signalName, execution.getActivityInstanceId(), (String) signalData);
}
} catch (SpinRuntimeException e) {
// We couldn't get the error code from the JSON, so we can only create an incident
log.warn("[{}] Error code not found. Creating incident.", execution.getProcessInstanceId());
execution.createIncident(signalName, execution.getActivityInstanceId(), (String) signalData);
}
} else if (signalName.equals(STATUS_TIMEOUT)) {
log.warn("[{}] Marking execution {} as timed out", execution.getProcessInstanceId(), execution.getId());
execution.createIncident(signalName, execution.getActivityInstanceId());
} else {
throw new RuntimeException("Unknown signal name: " + signalName);
}
}