diff --git a/gateway-ha/src/main/java/io/trino/gateway/ha/handler/RoutingTargetHandler.java b/gateway-ha/src/main/java/io/trino/gateway/ha/handler/RoutingTargetHandler.java index 5ca33b024..15abd2bcf 100644 --- a/gateway-ha/src/main/java/io/trino/gateway/ha/handler/RoutingTargetHandler.java +++ b/gateway-ha/src/main/java/io/trino/gateway/ha/handler/RoutingTargetHandler.java @@ -80,7 +80,7 @@ public RoutingTargetResponse resolveRouting(HttpServletRequest request) return new RoutingTargetResponse( new RoutingDestination(routingGroup, cluster, buildUriWithNewCluster(cluster, request), externalUrl), request); - }).orElse(getRoutingTargetResponse(request)); + }).orElseGet(() -> getRoutingTargetResponse(request)); logRewrite(routingTargetResponse.routingDestination().clusterHost(), request); return routingTargetResponse; diff --git a/gateway-ha/src/test/java/io/trino/gateway/ha/handler/TestRoutingTargetHandler.java b/gateway-ha/src/test/java/io/trino/gateway/ha/handler/TestRoutingTargetHandler.java index 277e0c2aa..7a2af86db 100644 --- a/gateway-ha/src/test/java/io/trino/gateway/ha/handler/TestRoutingTargetHandler.java +++ b/gateway-ha/src/test/java/io/trino/gateway/ha/handler/TestRoutingTargetHandler.java @@ -29,6 +29,7 @@ import jakarta.ws.rs.HttpMethod; import jakarta.ws.rs.WebApplicationException; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.extension.ExtendWith; @@ -108,7 +109,6 @@ void setUp() config = provideGatewayConfiguration(); httpClient = Mockito.mock(HttpClient.class); routingManager = Mockito.mock(RoutingManager.class); - when(routingManager.provideBackendConfiguration(any(), any())).thenReturn(new ProxyBackendConfiguration()); request = prepareMockRequest(); // Initialize the handler with the configuration @@ -117,6 +117,14 @@ void setUp() RoutingGroupSelector.byRoutingExternal(httpClient, config.getRoutingRules().getRulesExternalConfiguration(), config.getRequestAnalyzerConfig()), config); } + @BeforeEach + void resetMocks() + { + Mockito.reset(routingManager); + when(routingManager.provideBackendConfiguration(any(), any())).thenReturn(new ProxyBackendConfiguration()); + config.getRoutingRules().getRulesExternalConfiguration().setPropagateErrors(false); + } + @Test void testBasicHeaderModification() throws Exception @@ -300,6 +308,38 @@ void testPropagateErrorsTrueResponseGroupAndErrorsSet() .isInstanceOf(WebApplicationException.class); } + @Test + void testResolveRoutingWithKnownQueryIdAndFailingFallback() + { + // Simulate a request to /ui/query.html?queryId where the query ID is known + // but the fallback routing (getRoutingTargetResponse) would fail because + // there are no backends for the resolved routing group. + // This tests that the eagerly-evaluated fallback does not throw when + // previousCluster is present. + String queryId = "20240101_000000_00001_aaaaa"; + String backendUrl = "https://trino-backend.example.com"; + + HttpServletRequest uiRequest = Mockito.mock(HttpServletRequest.class); + when(uiRequest.getMethod()).thenReturn(HttpMethod.GET); + when(uiRequest.getRequestURI()).thenReturn("/ui/query.html"); + when(uiRequest.getQueryString()).thenReturn(queryId); + + // Query ID is known — cache returns the backend + when(routingManager.findBackendForQueryId(queryId)).thenReturn(backendUrl); + when(routingManager.findRoutingGroupForQueryId(queryId)).thenReturn("test-group"); + when(routingManager.findExternalUrlForQueryId(queryId)).thenReturn(backendUrl); + + // Fallback routing would throw (no backends for the routing group) + when(routingManager.provideBackendConfiguration(any(), any())) + .thenThrow(new IllegalStateException("Number of active backends found zero")); + + // With orElse(), this throws. With orElseGet(), this succeeds. + // ref: https://github.com/trinodb/trino-gateway/issues/920 + RoutingTargetResponse response = handler.resolveRouting(uiRequest); + + assertThat(response.routingDestination().clusterHost()).isEqualTo(backendUrl); + } + private RoutingTargetHandler createHandlerWithPropagateErrorsTrue() { config.getRoutingRules().getRulesExternalConfiguration().setPropagateErrors(true);