Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bug fix - V1 canHandle() should cater maxWaitTime #5

Merged
merged 1 commit into from
Apr 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -55,24 +55,24 @@
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.9</version>
<version>2.0.13</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.0.9</version>
<version>2.0.13</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.muserver</groupId>
<artifactId>mu-server</artifactId>
<version>0.74.3</version>
<version>1.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20231013</version>
<version>20240303</version>
<scope>test</scope>
</dependency>
<dependency>
Expand All @@ -90,7 +90,7 @@
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.1</version>
<version>5.10.2</version>
<scope>test</scope>
</dependency>

Expand All @@ -109,7 +109,7 @@
<dependency>
<groupId>com.hsbc.cranker</groupId>
<artifactId>cranker-connector</artifactId>
<version>1.2.3</version>
<version>1.2.4</version>
<scope>test</scope>
</dependency>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<String, Object> toMap();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<ConnectorConnection> connections();

/**
* Dark mode status
* @return Returns <code>true</code> if this connector is on a dark mode host; otherwise <code>false</code>.
*/
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<String,Object> toMap();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,32 @@
public interface ConnectorService {

/**
* The path prefix of the service.
* @return The path prefix of the service, or &quot;*&quot; 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<ConnectorInstance> 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<String,Object> toMap();
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/com/hsbc/cranker/mucranker/CrankerRouter.java
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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. <code>1.0.0</code>
*/
static String muCrankerVersion() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ public class CrankerRouterBuilder {
private RouteResolver routeResolver;
private List<String> supportedCrankerProtocol = List.of("1.0", "3.0");

private CrankerRouterBuilder() {}

/**
* Create a CrankerRouterBuilder
* @return A new builder
*/
public static CrankerRouterBuilder crankerRouter() {
Expand Down Expand Up @@ -225,6 +228,7 @@ public CrankerRouterBuilder withSupportedCrankerProtocols(List<String> protocols


/**
* Create a newly created CrankerRouter object
* @return A newly created CrankerRouter object
*/
public CrankerRouter start() {
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/com/hsbc/cranker/mucranker/DarkHost.java
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/com/hsbc/cranker/mucranker/ProxyInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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();
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/com/hsbc/cranker/mucranker/RouterInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<ConnectorService> services();
Expand All @@ -32,6 +33,7 @@ public interface RouterInfo {
Map<String, Object> 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<DarkHost> darkHosts();
Expand Down
10 changes: 6 additions & 4 deletions src/main/java/com/hsbc/cranker/mucranker/WebSocketFarm.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 -> {
Expand All @@ -75,7 +75,9 @@ public boolean canHandle(String target, boolean useCatchAll) {
final String routeKey = resolveRouteKey(target, useCatchAll);
if (routeKey == null) return false;
final Queue<RouterSocket> 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() {
Expand Down Expand Up @@ -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<WaitingSocketTask> 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);
Expand Down Expand Up @@ -253,7 +255,7 @@ static void logIfFail(ThrowingFunction f) {
}
}

private class WaitingSocketTask {
private static class WaitingSocketTask {

private final String target;
private Consumer<RouterSocket> successListener;
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/com/hsbc/cranker/mucranker/WebSocketFarmV3.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 -> {
Expand All @@ -63,7 +63,7 @@ public boolean canHandle(String target, boolean useCatchAll) {
final String routeKey = resolveRouteKey(target, useCatchAll);
if (routeKey == null) return false;
final List<RouterSocketV3> routeSockets = sockets.get(routeKey);
return routeSockets != null && routeSockets.size() > 0;
return routeSockets != null && !routeSockets.isEmpty();
}

private String resolveRouteKey(String target, boolean useCatchAll) {
Expand Down Expand Up @@ -128,7 +128,7 @@ public CompletableFuture<RouterSocketV3> getWebSocket(String target, boolean use
}
List<RouterSocketV3> routeSockets = sockets.get(routeKey);

if (routeSockets == null || routeSockets.size() == 0) {
if (routeSockets == null || routeSockets.isEmpty()) {
future.complete(null);
return;
}
Expand Down
2 changes: 2 additions & 0 deletions src/test/java/RunLocal.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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();
Expand Down
19 changes: 19 additions & 0 deletions src/test/java/com/hsbc/cranker/mucranker/MultiConnectorTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<String, AtomicInteger> 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
Expand Down
Loading