refactor: DetailService uses ExecutionStore, tree built from parentProcessorId
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user