refactor: DetailService uses ExecutionStore, tree built from parentProcessorId

This commit is contained in:
hsiegeln
2026-03-16 18:18:53 +01:00
parent 84b93d74c7
commit adf4b44d78

View File

@@ -1,104 +1,61 @@
package com.cameleer3.server.core.detail;
import com.cameleer3.server.core.storage.ExecutionRepository;
import com.cameleer3.server.core.storage.ExecutionStore;
import com.cameleer3.server.core.storage.ExecutionStore.ProcessorRecord;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.*;
/**
* Provides execution detail with reconstructed processor tree.
* <p>
* This is a plain class (no Spring annotations) -- it lives in the core module
* and is wired as a bean by the app module configuration.
*/
public class DetailService {
private final ExecutionRepository repository;
private final ExecutionStore executionStore;
public DetailService(ExecutionRepository repository) {
this.repository = repository;
public DetailService(ExecutionStore executionStore) {
this.executionStore = executionStore;
}
/**
* Get the full detail of a route execution, including the nested processor tree.
*
* @param executionId the execution ID to look up
* @return the execution detail, or empty if not found
*/
public Optional<ExecutionDetail> getDetail(String executionId) {
return repository.findRawById(executionId)
.map(this::toDetail);
return executionStore.findById(executionId)
.map(exec -> {
List<ProcessorRecord> processors = executionStore.findProcessors(executionId);
List<ProcessorNode> roots = buildTree(processors);
return new ExecutionDetail(
exec.executionId(), exec.routeId(), exec.agentId(),
exec.status(), exec.startTime(), exec.endTime(),
exec.durationMs() != null ? exec.durationMs() : 0L,
exec.correlationId(), exec.exchangeId(),
exec.errorMessage(), exec.errorStacktrace(),
exec.diagramContentHash(), roots
);
});
}
private ExecutionDetail toDetail(RawExecutionRow row) {
List<ProcessorNode> roots = reconstructTree(
row.processorIds(),
row.processorTypes(),
row.processorStatuses(),
row.processorStarts(),
row.processorEnds(),
row.processorDurations(),
row.processorDiagramNodeIds(),
row.processorErrorMessages(),
row.processorErrorStacktraces(),
row.processorDepths(),
row.processorParentIndexes()
);
List<ProcessorNode> buildTree(List<ProcessorRecord> processors) {
if (processors.isEmpty()) return List.of();
return new ExecutionDetail(
row.executionId(),
row.routeId(),
row.agentId(),
row.status(),
row.startTime(),
row.endTime(),
row.durationMs(),
row.correlationId(),
row.exchangeId(),
row.errorMessage(),
row.errorStackTrace(),
row.diagramContentHash(),
roots
);
}
/**
* Reconstruct the nested processor tree from flat parallel arrays.
* <p>
* Uses parentIndexes to wire children: parentIndex == -1 means the node is a root.
* Otherwise, parentIndex is the array index of the parent node.
*/
List<ProcessorNode> reconstructTree(
String[] ids, String[] types, String[] statuses,
java.time.Instant[] starts, java.time.Instant[] ends, long[] durations,
String[] diagramNodeIds, String[] errorMessages, String[] errorStacktraces,
int[] depths, int[] parentIndexes) {
if (ids == null || ids.length == 0) {
return List.of();
}
int len = ids.length;
ProcessorNode[] nodes = new ProcessorNode[len];
for (int i = 0; i < len; i++) {
nodes[i] = new ProcessorNode(
ids[i], types[i], statuses[i],
starts[i], ends[i], durations[i],
diagramNodeIds[i], errorMessages[i], errorStacktraces[i]
);
Map<String, ProcessorNode> nodeMap = new LinkedHashMap<>();
for (ProcessorRecord p : processors) {
nodeMap.put(p.processorId(), new ProcessorNode(
p.processorId(), p.processorType(), p.status(),
p.startTime(), p.endTime(),
p.durationMs() != null ? p.durationMs() : 0L,
p.diagramNodeId(), p.errorMessage(), p.errorStacktrace()
));
}
List<ProcessorNode> roots = new ArrayList<>();
for (int i = 0; i < len; i++) {
if (parentIndexes[i] == -1) {
roots.add(nodes[i]);
for (ProcessorRecord p : processors) {
ProcessorNode node = nodeMap.get(p.processorId());
if (p.parentProcessorId() == null) {
roots.add(node);
} else {
nodes[parentIndexes[i]].addChild(nodes[i]);
ProcessorNode parent = nodeMap.get(p.parentProcessorId());
if (parent != null) {
parent.addChild(node);
} else {
roots.add(node); // orphan safety
}
}
}
return roots;
}
}