feat: persist and expose resolvedEndpointUri for execution-level drill-down

Wire resolvedEndpointUri through the full chain:
- V9 migration adds resolved_endpoint_uri column
- IngestionService extracts from ProcessorExecution
- PostgresExecutionStore persists and reads the column
- ProcessorNode includes field in detail API response
- UI schema updated for ProcessorNode and PositionedNode

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-03-28 18:37:11 +01:00
parent e5e6175aca
commit c4b396e618
7 changed files with 23 additions and 9 deletions

View File

@@ -73,8 +73,9 @@ public class PostgresExecutionStore implements ExecutionStore {
application_name, route_id, depth, parent_processor_id,
status, start_time, end_time, duration_ms, error_message, error_stacktrace,
input_body, output_body, input_headers, output_headers, attributes,
loop_index, loop_size, split_index, split_size, multicast_index)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?::jsonb, ?::jsonb, ?::jsonb, ?, ?, ?, ?, ?)
loop_index, loop_size, split_index, split_size, multicast_index,
resolved_endpoint_uri)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?::jsonb, ?::jsonb, ?::jsonb, ?, ?, ?, ?, ?, ?)
ON CONFLICT (execution_id, processor_id, start_time) DO UPDATE SET
status = EXCLUDED.status,
end_time = COALESCE(EXCLUDED.end_time, processor_executions.end_time),
@@ -90,7 +91,8 @@ public class PostgresExecutionStore implements ExecutionStore {
loop_size = COALESCE(EXCLUDED.loop_size, processor_executions.loop_size),
split_index = COALESCE(EXCLUDED.split_index, processor_executions.split_index),
split_size = COALESCE(EXCLUDED.split_size, processor_executions.split_size),
multicast_index = COALESCE(EXCLUDED.multicast_index, processor_executions.multicast_index)
multicast_index = COALESCE(EXCLUDED.multicast_index, processor_executions.multicast_index),
resolved_endpoint_uri = COALESCE(EXCLUDED.resolved_endpoint_uri, processor_executions.resolved_endpoint_uri)
""",
processors.stream().map(p -> new Object[]{
p.executionId(), p.processorId(), p.processorType(),
@@ -102,7 +104,8 @@ public class PostgresExecutionStore implements ExecutionStore {
p.inputBody(), p.outputBody(), p.inputHeaders(), p.outputHeaders(),
p.attributes(),
p.loopIndex(), p.loopSize(), p.splitIndex(), p.splitSize(),
p.multicastIndex()
p.multicastIndex(),
p.resolvedEndpointUri()
}).toList());
}
@@ -160,7 +163,8 @@ public class PostgresExecutionStore implements ExecutionStore {
rs.getObject("loop_size") != null ? rs.getInt("loop_size") : null,
rs.getObject("split_index") != null ? rs.getInt("split_index") : null,
rs.getObject("split_size") != null ? rs.getInt("split_size") : null,
rs.getObject("multicast_index") != null ? rs.getInt("multicast_index") : null);
rs.getObject("multicast_index") != null ? rs.getInt("multicast_index") : null,
rs.getString("resolved_endpoint_uri"));
private static Instant toInstant(ResultSet rs, String column) throws SQLException {
Timestamp ts = rs.getTimestamp(column);

View File

@@ -0,0 +1 @@
ALTER TABLE processor_executions ADD COLUMN resolved_endpoint_uri TEXT;

View File

@@ -63,7 +63,8 @@ public class DetailService {
parseAttributes(p.attributes()),
p.loopIndex(), p.loopSize(),
p.splitIndex(), p.splitSize(),
p.multicastIndex()
p.multicastIndex(),
p.resolvedEndpointUri()
));
}

View File

@@ -27,6 +27,7 @@ public final class ProcessorNode {
private final Integer splitIndex;
private final Integer splitSize;
private final Integer multicastIndex;
private final String resolvedEndpointUri;
private final List<ProcessorNode> children;
public ProcessorNode(String processorId, String processorType, String status,
@@ -35,7 +36,8 @@ public final class ProcessorNode {
Map<String, String> attributes,
Integer loopIndex, Integer loopSize,
Integer splitIndex, Integer splitSize,
Integer multicastIndex) {
Integer multicastIndex,
String resolvedEndpointUri) {
this.processorId = processorId;
this.processorType = processorType;
this.status = status;
@@ -50,6 +52,7 @@ public final class ProcessorNode {
this.splitIndex = splitIndex;
this.splitSize = splitSize;
this.multicastIndex = multicastIndex;
this.resolvedEndpointUri = resolvedEndpointUri;
this.children = new ArrayList<>();
}
@@ -71,5 +74,6 @@ public final class ProcessorNode {
public Integer getSplitIndex() { return splitIndex; }
public Integer getSplitSize() { return splitSize; }
public Integer getMulticastIndex() { return multicastIndex; }
public String getResolvedEndpointUri() { return resolvedEndpointUri; }
public List<ProcessorNode> getChildren() { return List.copyOf(children); }
}

View File

@@ -131,7 +131,8 @@ public class IngestionService {
toJson(p.getAttributes()),
p.getLoopIndex(), p.getLoopSize(),
p.getSplitIndex(), p.getSplitSize(),
p.getMulticastIndex()
p.getMulticastIndex(),
p.getResolvedEndpointUri()
));
if (p.getChildren() != null) {
flat.addAll(flattenProcessors(

View File

@@ -38,6 +38,7 @@ public interface ExecutionStore {
String attributes,
Integer loopIndex, Integer loopSize,
Integer splitIndex, Integer splitSize,
Integer multicastIndex
Integer multicastIndex,
String resolvedEndpointUri
) {}
}

View File

@@ -1652,6 +1652,7 @@ export interface components {
attributes: {
[key: string]: string;
};
resolvedEndpointUri?: string;
children: components["schemas"]["ProcessorNode"][];
};
DiagramLayout: {
@@ -1680,6 +1681,7 @@ export interface components {
width?: number;
/** Format: double */
height?: number;
endpointUri?: string;
};
/** @description OIDC configuration for SPA login flow */
OidcPublicConfigResponse: {