use of ru.fix.completable.reactor.runtime.immutability.ImmutabilityControlLevel in project completable-reactor by ru-fix.
the class ReactorGraphExecutionBuilder method handle.
private <PayloadType> void handle(ProcessingVertex processingVertex, TransitionPayloadContext payloadContext, CompletableFuture<PayloadType> executionResultFuture) {
CRReactorGraph.ProcessingItemInfo processorInfo = processingVertex.getProcessingItemInfo();
Object payload = payloadContext.getPayload();
/**
* In case of detached merge point processor should not have incoming handling transition.
*/
if (processorInfo.getProcessingItemType() == CRReactorGraph.ProcessingItemType.MERGE_POINT) {
throw new IllegalStateException(String.format("Processor %s is of type %s and should not have any incoming handling transition", processingVertex.getProcessingItem().getDebugName(), processorInfo.getProcessingItemType()));
}
ProfiledCall handleCall = profiler.profiledCall(ProfilerNames.HANDLE + "." + (payload != null ? payload.getClass().getSimpleName() : "null") + "." + processingVertex.getProcessingItem().getProfilingName()).start();
boolean isTraceablePayload = tracer.isTraceable(payload);
Object handleTracingMarker = isTraceablePayload ? tracer.beforeHandle(processingVertex.getProcessingItem().getIdentity().toString(), payload) : null;
ReactorGraphModel.Identity handleTracingIdentity = isTraceablePayload ? processingVertex.getProcessingItem().getIdentity() : null;
CompletableFuture<?> handlingResult;
/**
* Immutability check ensures that there is no payload modification during handling.
*/
final ImmutabilityControlLevel controlLevel = this.immutabilityControlLevel;
ImmutabilityChecker.Snapshot payloadSnapshot;
try {
if (controlLevel != ImmutabilityControlLevel.NO_CONTROL) {
/**
* Invoke handling with immutability check.
*/
payloadSnapshot = immutabilityChecker.takeSnapshot(payload);
handlingResult = invokeHandlingMethod(processorInfo, processingVertex.getProcessingItem(), payload);
} else {
/**
* Invoke handling without immutability check.
*/
payloadSnapshot = null;
handlingResult = invokeHandlingMethod(processorInfo, processingVertex.getProcessingItem(), payload);
}
} catch (Exception handlingException) {
RuntimeException exc = new RuntimeException(String.format("Failed handling by processor %s for payload %s %s. Handling method raised exception: %s.", processingVertex.getProcessingItem().getDebugName(), payload.getClass(), debugSerializer.dumpObject(payload), handlingException), handlingException);
log.error(exc.getMessage(), exc);
executionResultFuture.completeExceptionally(exc);
processingVertex.getProcessorFuture().complete(new HandlePayloadContext().setTerminal(true));
return;
}
if (handlingResult == null) {
RuntimeException exc = new RuntimeException(String.format("Failed handling by processor %s for payload %s %s. Handling method returned NULL." + " Instance of CompletableFuture expected.", processingVertex.getProcessingItem().getDebugName(), payload.getClass(), debugSerializer.dumpObject(payload)));
log.error(exc.getMessage(), exc);
executionResultFuture.completeExceptionally(exc);
processingVertex.getProcessorFuture().complete(new HandlePayloadContext().setTerminal(true));
return;
}
handlingResult.handleAsync((res, thr) -> {
handleCall.stop();
if (isTraceablePayload) {
tracer.afterHandle(handleTracingMarker, handleTracingIdentity.toString(), res, thr);
}
if (controlLevel != ImmutabilityControlLevel.NO_CONTROL) {
Optional<String> diff = immutabilityChecker.diff(payloadSnapshot, payload);
if (diff.isPresent()) {
String message = String.format("Concurrent modification of payload %s detected. Diff: %s.", debugSerializer.dumpObject(payload), diff.get());
switch(controlLevel) {
case LOG_ERROR:
log.error(message);
break;
case LOG_WARN:
log.warn(message);
break;
case EXCEPTION:
RuntimeException immutabilityException = new RuntimeException(message);
log.error(message, immutabilityException);
if (thr == null) {
log.error("Overwriting execution exception {} by immutability check exception {}.", thr, immutabilityException, thr);
}
thr = immutabilityException;
break;
}
}
}
if (thr != null) {
RuntimeException exc = new RuntimeException(String.format("Failed handling by processor %s for payload %s %s", processingVertex.getProcessingItem().getDebugName(), payload.getClass(), debugSerializer.dumpObject(payload)), thr);
log.error(exc.getMessage(), exc);
executionResultFuture.completeExceptionally(exc);
processingVertex.getProcessorFuture().complete(new HandlePayloadContext().setTerminal(true));
} else {
processingVertex.getProcessorFuture().complete(new HandlePayloadContext().setPayload(payload).setProcessorResult(res));
}
return null;
}).exceptionally(exc -> {
log.error("Failed to execute afterHandle block for {}", Optional.of(processingVertex).map(ProcessingVertex::getProcessingItem).map(CRProcessingItem::getDebugName).orElse("?"), exc);
return null;
});
}
Aggregations