Time electrum requests, and move on to another server if one takes more than 1000ms on average to respond (measured over the last 5 requests).

This commit is contained in:
CalDescent 2022-02-11 18:02:56 +00:00
parent dbacfb964b
commit 9b43e4ea3d

View File

@ -5,19 +5,7 @@ import java.math.BigDecimal;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.Socket; import java.net.Socket;
import java.net.SocketAddress; import java.net.SocketAddress;
import java.util.ArrayList; import java.util.*;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Random;
import java.util.Scanner;
import java.util.Set;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -50,6 +38,9 @@ public class ElectrumX extends BitcoinyBlockchainProvider {
/** Error message sent by some ElectrumX servers when they don't support returning verbose transactions. */ /** Error message sent by some ElectrumX servers when they don't support returning verbose transactions. */
private static final String VERBOSE_TRANSACTIONS_UNSUPPORTED_MESSAGE = "verbose transactions are currently unsupported"; private static final String VERBOSE_TRANSACTIONS_UNSUPPORTED_MESSAGE = "verbose transactions are currently unsupported";
private static final int RESPONSE_TIME_READINGS = 5;
private static final long MAX_AVG_RESPONSE_TIME = 1000L; // ms
public static class Server { public static class Server {
String hostname; String hostname;
@ -57,6 +48,7 @@ public class ElectrumX extends BitcoinyBlockchainProvider {
ConnectionType connectionType; ConnectionType connectionType;
int port; int port;
private List<Long> responseTimes = new ArrayList<>();
public Server(String hostname, ConnectionType connectionType, int port) { public Server(String hostname, ConnectionType connectionType, int port) {
this.hostname = hostname; this.hostname = hostname;
@ -64,6 +56,25 @@ public class ElectrumX extends BitcoinyBlockchainProvider {
this.port = port; this.port = port;
} }
public void addResponseTime(long responseTime) {
while (this.responseTimes.size() > RESPONSE_TIME_READINGS) {
this.responseTimes.remove(0);
}
this.responseTimes.add(responseTime);
}
public long averageResponseTime() {
if (this.responseTimes.size() < RESPONSE_TIME_READINGS) {
// Not enough readings yet
return 0L;
}
OptionalDouble average = this.responseTimes.stream().mapToDouble(a -> a).average();
if (average.isPresent()) {
return Double.valueOf(average.getAsDouble()).longValue();
}
return 0L;
}
@Override @Override
public boolean equals(Object other) { public boolean equals(Object other) {
if (other == this) if (other == this)
@ -539,6 +550,17 @@ public class ElectrumX extends BitcoinyBlockchainProvider {
while (haveConnection()) { while (haveConnection()) {
Object response = connectedRpc(method, params); Object response = connectedRpc(method, params);
// If we have more servers and this one replied slowly, try another
if (!this.remainingServers.isEmpty()) {
long averageResponseTime = this.currentServer.averageResponseTime();
if (averageResponseTime > MAX_AVG_RESPONSE_TIME) {
LOGGER.info("Slow average response time {}ms from {} - trying another server...", this.currentServer.hostname, averageResponseTime);
this.closeServer();
break;
}
}
if (response != null) if (response != null)
return response; return response;
@ -628,6 +650,7 @@ public class ElectrumX extends BitcoinyBlockchainProvider {
String request = requestJson.toJSONString() + "\n"; String request = requestJson.toJSONString() + "\n";
LOGGER.trace(() -> String.format("Request: %s", request)); LOGGER.trace(() -> String.format("Request: %s", request));
long startTime = System.currentTimeMillis();
final String response; final String response;
try { try {
@ -638,7 +661,11 @@ public class ElectrumX extends BitcoinyBlockchainProvider {
return null; return null;
} }
long endTime = System.currentTimeMillis();
long responseTime = endTime-startTime;
LOGGER.trace(() -> String.format("Response: %s", response)); LOGGER.trace(() -> String.format("Response: %s", response));
LOGGER.info(() -> String.format("Time taken: %dms", endTime-startTime));
if (response.isEmpty()) if (response.isEmpty())
// Empty response - try another server? // Empty response - try another server?
@ -649,6 +676,11 @@ public class ElectrumX extends BitcoinyBlockchainProvider {
// Unexpected response - try another server? // Unexpected response - try another server?
return null; return null;
// Keep track of response times
if (this.currentServer != null) {
this.currentServer.addResponseTime(responseTime);
}
JSONObject responseJson = (JSONObject) responseObj; JSONObject responseJson = (JSONObject) responseObj;
Object errorObj = responseJson.get("error"); Object errorObj = responseJson.get("error");