From 2519d20361b8b03dae8851e4da42befe102f9112 Mon Sep 17 00:00:00 2001 From: Jay LU Date: Sun, 28 Apr 2024 10:23:13 +0800 Subject: [PATCH] bug fix - V1 canHandle() should cater maxWaitTime --- pom.xml | 12 ++++++------ .../mucranker/ConnectorConnection.java | 3 +++ .../cranker/mucranker/ConnectorInstance.java | 5 +++++ .../cranker/mucranker/ConnectorService.java | 5 +++++ .../hsbc/cranker/mucranker/CrankerRouter.java | 3 +++ .../mucranker/CrankerRouterBuilder.java | 4 ++++ .../com/hsbc/cranker/mucranker/DarkHost.java | 2 ++ .../mucranker/LongestFirstRouteResolver.java | 5 +++++ .../com/hsbc/cranker/mucranker/ProxyInfo.java | 10 ++++++++++ .../hsbc/cranker/mucranker/RouterInfo.java | 2 ++ .../hsbc/cranker/mucranker/WebSocketFarm.java | 10 ++++++---- .../cranker/mucranker/WebSocketFarmV3.java | 6 +++--- src/test/java/RunLocal.java | 2 ++ .../cranker/mucranker/MultiConnectorTest.java | 19 +++++++++++++++++++ 14 files changed, 75 insertions(+), 13 deletions(-) diff --git a/pom.xml b/pom.xml index ae5273b..8286d1a 100644 --- a/pom.xml +++ b/pom.xml @@ -55,24 +55,24 @@ org.slf4j slf4j-api - 2.0.9 + 2.0.13 org.slf4j slf4j-simple - 2.0.9 + 2.0.13 test io.muserver mu-server - 0.74.3 + 1.1.0 provided org.json json - 20231013 + 20240303 test @@ -90,7 +90,7 @@ org.junit.jupiter junit-jupiter - 5.10.1 + 5.10.2 test @@ -109,7 +109,7 @@ com.hsbc.cranker cranker-connector - 1.2.3 + 1.2.4 test diff --git a/src/main/java/com/hsbc/cranker/mucranker/ConnectorConnection.java b/src/main/java/com/hsbc/cranker/mucranker/ConnectorConnection.java index 21597a8..5879705 100644 --- a/src/main/java/com/hsbc/cranker/mucranker/ConnectorConnection.java +++ b/src/main/java/com/hsbc/cranker/mucranker/ConnectorConnection.java @@ -9,16 +9,19 @@ public interface ConnectorConnection { /** + * A unique ID of this socket * @return A unique ID of this socket */ String socketID(); /** + * The port the socket is connected on * @return The port the socket is connected on */ int port(); /** + * the data in this object as a map * @return Returns the data in this object as a map */ HashMap toMap(); diff --git a/src/main/java/com/hsbc/cranker/mucranker/ConnectorInstance.java b/src/main/java/com/hsbc/cranker/mucranker/ConnectorInstance.java index 0d5c81e..92641a1 100644 --- a/src/main/java/com/hsbc/cranker/mucranker/ConnectorInstance.java +++ b/src/main/java/com/hsbc/cranker/mucranker/ConnectorInstance.java @@ -13,26 +13,31 @@ public interface ConnectorInstance { /** + * The IP address of the instance. * @return The IP address of the instance. */ String ip(); /** + * The unique ID of the connector. * @return The unique ID of the connector. */ String connectorInstanceID(); /** + * The current idle connections that this connector has registered to the router. * @return The current idle connections that this connector has registered to the router. */ List connections(); /** + * Dark mode status * @return Returns true if this connector is on a dark mode host; otherwise false. */ boolean darkMode(); /** + * The state of this object as a map of key-value pairs. * @return Returns the state of this object as a map of key-value pairs. */ Map toMap(); diff --git a/src/main/java/com/hsbc/cranker/mucranker/ConnectorService.java b/src/main/java/com/hsbc/cranker/mucranker/ConnectorService.java index ee09034..66c8d75 100644 --- a/src/main/java/com/hsbc/cranker/mucranker/ConnectorService.java +++ b/src/main/java/com/hsbc/cranker/mucranker/ConnectorService.java @@ -13,27 +13,32 @@ public interface ConnectorService { /** + * The path prefix of the service. * @return The path prefix of the service, or "*" if it is a catch-all service. * @see #isCatchAll() */ String route(); /** + * The component name that the connector registered * @return The component name that the connector registered */ String componentName(); /** + * The connectors that serve this route. * @return The connectors that serve this route. */ List connectors(); /** + * If this connector serves from the root of the URL path. * @return True if this connector serves from the root of the URL path */ boolean isCatchAll(); /** + * Gets this data has key-value pairs. * @return Gets this data has key-value pairs. */ Map toMap(); diff --git a/src/main/java/com/hsbc/cranker/mucranker/CrankerRouter.java b/src/main/java/com/hsbc/cranker/mucranker/CrankerRouter.java index 51c7949..fa9e632 100644 --- a/src/main/java/com/hsbc/cranker/mucranker/CrankerRouter.java +++ b/src/main/java/com/hsbc/cranker/mucranker/CrankerRouter.java @@ -17,6 +17,7 @@ public interface CrankerRouter { MuHandler createRegistrationHandler(); /** + * The total number of websocket connections for all routes that are currently connected and ready to receive requests * @return The total number of websocket connections for all routes that are currently connected and ready to receive requests */ int idleConnectionCount(); @@ -40,11 +41,13 @@ public interface CrankerRouter { void stop(); /** + * A manager that allows you to stop or start requests going to specific hosts. * @return A manager that allows you to stop or start requests going to specific hosts. */ DarkModeManager darkModeManager(); /** + * The version of mu-cranker-router being used. * @return The version of mu-cranker-router being used, e.g. 1.0.0 */ static String muCrankerVersion() { diff --git a/src/main/java/com/hsbc/cranker/mucranker/CrankerRouterBuilder.java b/src/main/java/com/hsbc/cranker/mucranker/CrankerRouterBuilder.java index 8cd45df..90c2dda 100644 --- a/src/main/java/com/hsbc/cranker/mucranker/CrankerRouterBuilder.java +++ b/src/main/java/com/hsbc/cranker/mucranker/CrankerRouterBuilder.java @@ -28,7 +28,10 @@ public class CrankerRouterBuilder { private RouteResolver routeResolver; private List supportedCrankerProtocol = List.of("1.0", "3.0"); + private CrankerRouterBuilder() {} + /** + * Create a CrankerRouterBuilder * @return A new builder */ public static CrankerRouterBuilder crankerRouter() { @@ -225,6 +228,7 @@ public CrankerRouterBuilder withSupportedCrankerProtocols(List protocols /** + * Create a newly created CrankerRouter object * @return A newly created CrankerRouter object */ public CrankerRouter start() { diff --git a/src/main/java/com/hsbc/cranker/mucranker/DarkHost.java b/src/main/java/com/hsbc/cranker/mucranker/DarkHost.java index 1c2a799..ea2c37b 100644 --- a/src/main/java/com/hsbc/cranker/mucranker/DarkHost.java +++ b/src/main/java/com/hsbc/cranker/mucranker/DarkHost.java @@ -16,11 +16,13 @@ public interface DarkHost { /** + * The address of the host * @return The address of the host */ InetAddress address(); /** + * The time that dark mode was turned on for this host * @return Returns the time that dark mode was turned on for this host */ Instant dateEnabled(); diff --git a/src/main/java/com/hsbc/cranker/mucranker/LongestFirstRouteResolver.java b/src/main/java/com/hsbc/cranker/mucranker/LongestFirstRouteResolver.java index 346d0f4..570d39d 100644 --- a/src/main/java/com/hsbc/cranker/mucranker/LongestFirstRouteResolver.java +++ b/src/main/java/com/hsbc/cranker/mucranker/LongestFirstRouteResolver.java @@ -7,6 +7,11 @@ */ public class LongestFirstRouteResolver implements RouteResolver{ + /** + * Constructor for LongestFirstRouteResolver + */ + public LongestFirstRouteResolver() {} + /** * Algorithm: using the longest route to match from the existing routes. * diff --git a/src/main/java/com/hsbc/cranker/mucranker/ProxyInfo.java b/src/main/java/com/hsbc/cranker/mucranker/ProxyInfo.java index 86ade13..ee08cc8 100644 --- a/src/main/java/com/hsbc/cranker/mucranker/ProxyInfo.java +++ b/src/main/java/com/hsbc/cranker/mucranker/ProxyInfo.java @@ -13,46 +13,55 @@ public interface ProxyInfo { /** + * isCatchAll * @return Returns true if the connector is a catch-all connector (i.e. the router of the connector is '*'). */ boolean isCatchAll(); /** + * A unique ID for the service connector. * @return A unique ID for the service connector. */ String connectorInstanceID(); /** + * The address of the service connector that this request is being proxied to. * @return The address of the service connector that this request is being proxied to. */ InetSocketAddress serviceAddress(); /** + * The cranker route (i.e. the first part of a path) for the request, or '*' if a catch-all connector is used. * @return The cranker route (i.e. the first part of a path) for the request, or '*' if a catch-all connector is used. */ String route(); /** + * The client's request to the router. * @return The client's request to the router. */ MuRequest request(); /** + * The router's response to the client. * @return The router's response to the client. */ MuResponse response(); /** + * The time in millis from when the router received the request until it sent the last response byte. * @return The time in millis from when the router received the request until it sent the last response byte. */ long durationMillis(); /** + * The number of bytes uploaded by the client in the request * @return The number of bytes uploaded by the client in the request */ long bytesReceived(); /** + * The number of bytes sent to the client on the response * @return The number of bytes sent to the client on the response */ long bytesSent(); @@ -73,6 +82,7 @@ public interface ProxyInfo { Throwable errorIfAny(); /** + * Wait time in millis seconds to get a websocket (which is used for proxy requests) * @return wait time in millis seconds to get a websocket (which is used for proxy requests) */ long socketWaitInMillis(); diff --git a/src/main/java/com/hsbc/cranker/mucranker/RouterInfo.java b/src/main/java/com/hsbc/cranker/mucranker/RouterInfo.java index 07ee558..9be1951 100644 --- a/src/main/java/com/hsbc/cranker/mucranker/RouterInfo.java +++ b/src/main/java/com/hsbc/cranker/mucranker/RouterInfo.java @@ -10,6 +10,7 @@ public interface RouterInfo { /** + * All the services that are registered with this cranker * @return All the services that are registered with this cranker */ List services(); @@ -32,6 +33,7 @@ public interface RouterInfo { Map toMap(); /** + * All the hosts that this router currently will not send requests to * @return All the hosts that this router currently will not send requests to */ Set darkHosts(); diff --git a/src/main/java/com/hsbc/cranker/mucranker/WebSocketFarm.java b/src/main/java/com/hsbc/cranker/mucranker/WebSocketFarm.java index c5dfec3..6791fe3 100644 --- a/src/main/java/com/hsbc/cranker/mucranker/WebSocketFarm.java +++ b/src/main/java/com/hsbc/cranker/mucranker/WebSocketFarm.java @@ -61,7 +61,7 @@ public void cleanRoutes(long routesKeepTimeMillis) { final long cutoffTime = System.currentTimeMillis() - routesKeepTimeMillis; this.sockets.entrySet().stream() .filter(entry -> entry.getValue() != null - && entry.getValue().size() == 0 + && entry.getValue().isEmpty() && routeLastRemovalTimes.containsKey(entry.getKey()) && routeLastRemovalTimes.get(entry.getKey()) < cutoffTime) .forEach(entry -> { @@ -75,7 +75,9 @@ public boolean canHandle(String target, boolean useCatchAll) { final String routeKey = resolveRouteKey(target, useCatchAll); if (routeKey == null) return false; final Queue routerSockets = sockets.get(routeKey); - return routerSockets != null && routerSockets.size() > 0; + if (routerSockets != null && !routerSockets.isEmpty()) return true; + return routeLastRemovalTimes.containsKey(routeKey) + && (System.currentTimeMillis() - routeLastRemovalTimes.get(routeKey) < this.maxWaitInMillis); } public int idleCount() { @@ -112,7 +114,7 @@ private void addWebSocketSync(String route, RouterSocket socket) { // if there are requests waiting for a socket to this route, then immediately pass the socket to the request final Queue waiting = waitingTasks.get(route); - if (waiting != null && waiting.size() > 0) { + if (waiting != null && !waiting.isEmpty()) { final WaitingSocketTask waitTask = waiting.poll(); if (waitTask != null) { waitTask.notifySuccess(socket); @@ -253,7 +255,7 @@ static void logIfFail(ThrowingFunction f) { } } - private class WaitingSocketTask { + private static class WaitingSocketTask { private final String target; private Consumer successListener; diff --git a/src/main/java/com/hsbc/cranker/mucranker/WebSocketFarmV3.java b/src/main/java/com/hsbc/cranker/mucranker/WebSocketFarmV3.java index 90a6114..91e184b 100644 --- a/src/main/java/com/hsbc/cranker/mucranker/WebSocketFarmV3.java +++ b/src/main/java/com/hsbc/cranker/mucranker/WebSocketFarmV3.java @@ -49,7 +49,7 @@ public void cleanRoutes(long routesKeepTimeMillis) { final long cutoffTime = System.currentTimeMillis() - routesKeepTimeMillis; this.sockets.entrySet().stream() .filter(entry -> entry.getValue() != null - && entry.getValue().size() == 0 + && entry.getValue().isEmpty() && routeLastRemovalTimes.containsKey(entry.getKey()) && routeLastRemovalTimes.get(entry.getKey()) < cutoffTime) .forEach(entry -> { @@ -63,7 +63,7 @@ public boolean canHandle(String target, boolean useCatchAll) { final String routeKey = resolveRouteKey(target, useCatchAll); if (routeKey == null) return false; final List routeSockets = sockets.get(routeKey); - return routeSockets != null && routeSockets.size() > 0; + return routeSockets != null && !routeSockets.isEmpty(); } private String resolveRouteKey(String target, boolean useCatchAll) { @@ -128,7 +128,7 @@ public CompletableFuture getWebSocket(String target, boolean use } List routeSockets = sockets.get(routeKey); - if (routeSockets == null || routeSockets.size() == 0) { + if (routeSockets == null || routeSockets.isEmpty()) { future.complete(null); return; } diff --git a/src/test/java/RunLocal.java b/src/test/java/RunLocal.java index a62f72f..a9c993a 100644 --- a/src/test/java/RunLocal.java +++ b/src/test/java/RunLocal.java @@ -5,6 +5,7 @@ import org.json.JSONObject; import java.io.IOException; +import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; @@ -17,6 +18,7 @@ public static void main(String[] args) throws IOException { // Use the mu-cranker-router builder to create a router object. CrankerRouter router = CrankerRouterBuilder.crankerRouter() + .withSupportedCrankerProtocols(List.of("cranker_3.0", "cranker_1.0")) .withIdleTimeout(5, TimeUnit.MINUTES) .withRegistrationIpValidator(ip -> true) .start(); diff --git a/src/test/java/com/hsbc/cranker/mucranker/MultiConnectorTest.java b/src/test/java/com/hsbc/cranker/mucranker/MultiConnectorTest.java index 8c9a6da..550a908 100644 --- a/src/test/java/com/hsbc/cranker/mucranker/MultiConnectorTest.java +++ b/src/test/java/com/hsbc/cranker/mucranker/MultiConnectorTest.java @@ -205,6 +205,25 @@ void connectorCanDistributedToDifferentConnector_V1useCatchAll_V3useSpecificRout assertThat(bodyMap.get("targetV3_1").get(), is(20)); } + @Test + void connectorCanDistributedToDifferentConnector_V3useCatchAll_V1useSpecificRouteTakeHigherPriority() { + // start v1 connector + targetV1_1 = httpServer() + .addHandler(Method.GET, "/my-service/hello", (request, response, pathParams) -> response.write("targetV1_1")) + .start(); + connectorV1_1 = startConnector("*", "my-service", targetV1_1, List.of("cranker_1.0")); + + // start another v3 connector + targetV3_1 = httpServer() + .addHandler(Method.GET, "/my-service/hello", (request, response, pathParams) -> response.write("targetV3_1")) + .start(); + connectorV3_1 = startConnector("*", "*", targetV3_1, List.of("cranker_3.0")); + + // specific route take higher priority + final HashMap bodyMap = callAndGroupByBody(router.uri().resolve("/my-service/hello"), 20, 1); + assertThat(bodyMap.get("targetV1_1").get(), is(20)); + } + @Test void connectorCanDistributedToDifferentConnector_V1useSpecificRouteTakeHigherPriority_V3useCatchAll() { // start v1 connector