fix(catalog): preserve fromEndpointUri for removed routes

Both catalog controllers resolved the from-endpoint URI via
findContentHashForRouteByAgents, which filtered by the currently-live
agent instance_ids. Routes removed between app versions therefore lost
their fromUri even though the diagram row still exists.

Route through findLatestContentHashForAppRoute so resolution depends
only on (app, env, route) — stays populated for historical routes.
CatalogController now resolves the per-row env slug up-front so the
fromUri lookup works even for cross-env queries against managed apps.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-04-23 19:01:19 +02:00
parent 480a53c80c
commit 0995ab35c4
2 changed files with 20 additions and 15 deletions

View File

@@ -196,7 +196,16 @@ public class CatalogController {
}
Set<String> routeIds = routesByApp.getOrDefault(slug, Set.of());
List<String> agentIds = agents.stream().map(AgentInfo::instanceId).toList();
// Resolve the env slug for this row early so fromUri can survive
// cross-env queries (env==null) against managed apps.
String rowEnvSlug = envSlug;
if (app != null && rowEnvSlug.isEmpty()) {
try {
rowEnvSlug = envService.getById(app.environmentId()).slug();
} catch (Exception ignored) {}
}
final String resolvedEnvSlug = rowEnvSlug;
// Routes
List<RouteSummary> routeSummaries = routeIds.stream()
@@ -204,7 +213,7 @@ public class CatalogController {
String key = slug + "/" + routeId;
long count = routeExchangeCounts.getOrDefault(key, 0L);
Instant lastSeen = routeLastSeen.get(key);
String fromUri = resolveFromEndpointUri(routeId, agentIds);
String fromUri = resolveFromEndpointUri(slug, routeId, resolvedEnvSlug);
String state = routeStateRegistry.getState(slug, routeId).name().toLowerCase();
String routeState = "started".equals(state) ? null : state;
return new RouteSummary(routeId, count, lastSeen, fromUri, routeState);
@@ -258,15 +267,9 @@ public class CatalogController {
String healthTooltip = buildHealthTooltip(app != null, deployStatus, agentHealth, agents.size());
String displayName = app != null ? app.displayName() : slug;
String appEnvSlug = envSlug;
if (app != null && appEnvSlug.isEmpty()) {
try {
appEnvSlug = envService.getById(app.environmentId()).slug();
} catch (Exception ignored) {}
}
catalog.add(new CatalogApp(
slug, displayName, app != null, appEnvSlug,
slug, displayName, app != null, resolvedEnvSlug,
health, healthTooltip, agents.size(), routeSummaries, agentSummaries,
totalExchanges, deploymentSummary
));
@@ -275,8 +278,11 @@ public class CatalogController {
return ResponseEntity.ok(catalog);
}
private String resolveFromEndpointUri(String routeId, List<String> agentIds) {
return diagramStore.findContentHashForRouteByAgents(routeId, agentIds)
private String resolveFromEndpointUri(String applicationId, String routeId, String environment) {
if (environment == null || environment.isBlank()) {
return null;
}
return diagramStore.findLatestContentHashForAppRoute(applicationId, routeId, environment)
.flatMap(diagramStore::findByContentHash)
.map(RouteGraph::getRoot)
.map(root -> root.getEndpointUri())

View File

@@ -132,13 +132,12 @@ public class RouteCatalogController {
List<AgentInfo> agents = agentsByApp.getOrDefault(appId, List.of());
Set<String> routeIds = routesByApp.getOrDefault(appId, Set.of());
List<String> agentIds = agents.stream().map(AgentInfo::instanceId).toList();
List<RouteSummary> routeSummaries = routeIds.stream()
.map(routeId -> {
String key = appId + "/" + routeId;
long count = routeExchangeCounts.getOrDefault(key, 0L);
Instant lastSeen = routeLastSeen.get(key);
String fromUri = resolveFromEndpointUri(routeId, agentIds);
String fromUri = resolveFromEndpointUri(appId, routeId, envSlug);
String state = routeStateRegistry.getState(appId, routeId).name().toLowerCase();
String routeState = "started".equals(state) ? null : state;
return new RouteSummary(routeId, count, lastSeen, fromUri, routeState);
@@ -160,8 +159,8 @@ public class RouteCatalogController {
return ResponseEntity.ok(catalog);
}
private String resolveFromEndpointUri(String routeId, List<String> agentIds) {
return diagramStore.findContentHashForRouteByAgents(routeId, agentIds)
private String resolveFromEndpointUri(String applicationId, String routeId, String environment) {
return diagramStore.findLatestContentHashForAppRoute(applicationId, routeId, environment)
.flatMap(diagramStore::findByContentHash)
.map(RouteGraph::getRoot)
.map(root -> root.getEndpointUri())