Skip to content

Commit

Permalink
Introduce the concept of recoverable errors and non recoverable errors
Browse files Browse the repository at this point in the history
  • Loading branch information
ml-james committed Oct 29, 2024
1 parent 69a859c commit 225fd58
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 51 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ public interface SolanaClientError
ErrorCode getErrorCode();

String getErrorMessage();

boolean isRecoverable();
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,8 @@ public SolanaClientResponse<String> requestAirdrop(final String address, final l
{
return new SolanaJsonRpcClientResponse<>(result.getError().getErrorCode(), result.getError().getErrorMessage());
}
else
{
return new SolanaJsonRpcClientResponse<>(result.getSuccess());
}

return new SolanaJsonRpcClientResponse<>(result.getSuccess());
}

@Override
Expand All @@ -84,10 +82,8 @@ public SolanaClientResponse<TransactionResponse> getTransaction(final String tra
{
return new SolanaJsonRpcClientResponse<>(result.getError().getErrorCode(), result.getError().getErrorMessage());
}
else
{
return new SolanaJsonRpcClientResponse<>(result.getSuccess());
}

return new SolanaJsonRpcClientResponse<>(result.getSuccess());
}

@Override
Expand All @@ -105,10 +101,8 @@ public SolanaClientResponse<String> sendTransaction(final String transactionBlob
{
return new SolanaJsonRpcClientResponse<>(result.getError().getErrorCode(), result.getError().getErrorMessage());
}
else
{
return new SolanaJsonRpcClientResponse<>(result.getSuccess());
}

return new SolanaJsonRpcClientResponse<>(result.getSuccess());
}

@Override
Expand All @@ -124,10 +118,8 @@ public SolanaClientResponse<Long> getBalance(final String address)
{
return new SolanaJsonRpcClientResponse<>(result.getError().getErrorCode(), result.getError().getErrorMessage());
}
else
{
return new SolanaJsonRpcClientResponse<>(result.getSuccess().getValue());
}

return new SolanaJsonRpcClientResponse<>(result.getSuccess().getValue());
}

@Override
Expand All @@ -144,10 +136,8 @@ public SolanaClientResponse<TokenAmount> getTokenAccountBalance(final String add
{
return new SolanaJsonRpcClientResponse<>(result.getError().getErrorCode(), result.getError().getErrorMessage());
}
else
{
return new SolanaJsonRpcClientResponse<>(result.getSuccess().getValue());
}

return new SolanaJsonRpcClientResponse<>(result.getSuccess().getValue());
}

@Override
Expand All @@ -165,10 +155,8 @@ public SolanaClientResponse<AccountInfo> getAccountInfo(final String address)
{
return new SolanaJsonRpcClientResponse<>(result.getError().getErrorCode(), result.getError().getErrorMessage());
}
else
{
return new SolanaJsonRpcClientResponse<>(result.getSuccess().getValue());
}

return new SolanaJsonRpcClientResponse<>(result.getSuccess().getValue());
}

@Override
Expand All @@ -182,10 +170,8 @@ public SolanaClientResponse<Long> getBlockHeight()
{
return new SolanaJsonRpcClientResponse<>(result.getError().getErrorCode(), result.getError().getErrorMessage());
}
else
{
return new SolanaJsonRpcClientResponse<>(result.getSuccess());
}

return new SolanaJsonRpcClientResponse<>(result.getSuccess());
}

@Override
Expand All @@ -199,10 +185,8 @@ public SolanaClientResponse<Long> getSlot()
{
return new SolanaJsonRpcClientResponse<>(result.getError().getErrorCode(), result.getError().getErrorMessage());
}
else
{
return new SolanaJsonRpcClientResponse<>(result.getSuccess());
}

return new SolanaJsonRpcClientResponse<>(result.getSuccess());
}

@Override
Expand All @@ -216,10 +200,8 @@ public SolanaClientResponse<Blockhash> getLatestBlockhash()
{
return new SolanaJsonRpcClientResponse<>(result.getError().getErrorCode(), result.getError().getErrorMessage());
}
else
{
return new SolanaJsonRpcClientResponse<>(result.getSuccess().getValue());
}

return new SolanaJsonRpcClientResponse<>(result.getSuccess().getValue());
}

@Override
Expand All @@ -233,10 +215,8 @@ public SolanaClientResponse<Long> getMinimumBalanceForRentExemption(final int si
{
return new SolanaJsonRpcClientResponse<>(result.getError().getErrorCode(), result.getError().getErrorMessage());
}
else
{
return new SolanaJsonRpcClientResponse<>(result.getSuccess());
}

return new SolanaJsonRpcClientResponse<>(result.getSuccess());
}

private <T> Result<SolanaClientError, T> queryForObject(final TypeReference<RpcWrapperDTO<T>> type, final String method, final Object... params)
Expand All @@ -262,7 +242,7 @@ private Result<SolanaClientError, HttpRequest> prepareRequest(final String metho
}
catch (final JsonProcessingException e)
{
return Result.error(new SolanaJsonRpcClientError(
return Result.error(new SolanaUnrecoverableJsonRpcClientError(
ErrorCode.JSON_PROCESSING_ERROR,
String.format("Unable to encode JSON RPC request for method %s and params %s.", method, Arrays.toString(params)))
);
Expand All @@ -276,9 +256,13 @@ private Result<SolanaClientError, HttpResponse<String>> sendRequest(final String
final HttpResponse<String> httpResponse = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
if (httpResponse.statusCode() != 200)
{
return Result.error(new SolanaJsonRpcClientError(
return Result.error(new SolanaUnrecoverableJsonRpcClientError(
ErrorCode.JSON_RPC_UNEXPECTED_STATUS_CODE,
String.format("Unexpected status code returned from the JSON RPC for method %s and params %s.", method, Arrays.toString(params)))
String.format("Unexpected status code returned from the JSON RPC for method %s and params %s. The status code was %s with message %s.",
method,
Arrays.toString(params),
httpResponse.statusCode(),
httpResponse.body()))
);
}
else
Expand All @@ -288,7 +272,7 @@ private Result<SolanaClientError, HttpResponse<String>> sendRequest(final String
}
catch (final IOException | InterruptedException e)
{
return Result.error(new SolanaJsonRpcClientError(
return Result.error(new SolanaRecoverableJsonRpcClientError(
ErrorCode.JSON_RPC_COMMUNICATIONS_FAILURE,
String.format("Unable to communicate with the JSON RPC for method %s and params %s.", method, Arrays.toString(params)))
);
Expand All @@ -306,7 +290,7 @@ private <T> Result<SolanaClientError, T> decodeResponse(
final RpcWrapperDTO<T> rpcResult = solanaCodec.decodeResponse(httpResponse.body().getBytes(StandardCharsets.UTF_8), type);
if (rpcResult.getError() != null)
{
return Result.error(new SolanaJsonRpcClientError(
return Result.error(new SolanaUnrecoverableJsonRpcClientError(
ErrorCode.JSON_RPC_REPORTED_ERROR,
String.format("An error was reported by the JSON RPC with code %s and message %s.", rpcResult.getError().getCode(), rpcResult.getError().getMessage()))
);
Expand All @@ -315,7 +299,7 @@ private <T> Result<SolanaClientError, T> decodeResponse(
}
catch (final IOException e)
{
return Result.error(new SolanaJsonRpcClientError(
return Result.error(new SolanaUnrecoverableJsonRpcClientError(
ErrorCode.JSON_PROCESSING_ERROR,
String.format("Unable to decode JSON RPC response for method %s and params %s.", method, Arrays.toString(params)))
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
class SolanaJsonRpcClientResponse<T> implements SolanaClientResponse<T>
{
private final T response;
private final SolanaJsonRpcClientError error;
private final SolanaRecoverableJsonRpcClientError error;

SolanaJsonRpcClientResponse(final T response)
{
Expand All @@ -18,7 +18,7 @@ class SolanaJsonRpcClientResponse<T> implements SolanaClientResponse<T>
SolanaJsonRpcClientResponse(final ErrorCode errorCode, final String errorMessage)
{
this.response = null;
this.error = new SolanaJsonRpcClientError(errorCode, errorMessage);
this.error = new SolanaRecoverableJsonRpcClientError(errorCode, errorMessage);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
import com.lmax.solana4j.client.api.ErrorCode;
import com.lmax.solana4j.client.api.SolanaClientError;

class SolanaJsonRpcClientError implements SolanaClientError
class SolanaRecoverableJsonRpcClientError implements SolanaClientError
{
private final ErrorCode errorCode;
private final String errorMessage;

SolanaJsonRpcClientError(final ErrorCode errorCode, final String errorMessage)
SolanaRecoverableJsonRpcClientError(final ErrorCode errorCode, final String errorMessage)
{
this.errorCode = errorCode;
this.errorMessage = errorMessage;
Expand All @@ -25,4 +25,10 @@ public String getErrorMessage()
{
return errorMessage;
}

@Override
public boolean isRecoverable()
{
return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.lmax.solana4j.client.jsonrpc;

import com.lmax.solana4j.client.api.ErrorCode;
import com.lmax.solana4j.client.api.SolanaClientError;

class SolanaUnrecoverableJsonRpcClientError implements SolanaClientError
{
private final ErrorCode errorCode;
private final String errorMessage;

SolanaUnrecoverableJsonRpcClientError(final ErrorCode errorCode, final String errorMessage)
{
this.errorCode = errorCode;
this.errorMessage = errorMessage;
}

@Override
public ErrorCode getErrorCode()
{
return errorCode;
}

@Override
public String getErrorMessage()
{
return errorMessage;
}

@Override
public boolean isRecoverable()
{
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -423,10 +423,16 @@ private <T> T retryingClient(final SolanaClientResponse<T> response)
{
return response.getResponse();
}
else
else if (response.getError().isRecoverable())
{
LockSupport.parkNanos(100_000);
}
else
{
throw new RuntimeException(String.format("The error was not recoverable so not retrying. The error code was %s, with message %s.",
response.getError().getErrorMessage(),
response.getError().getErrorCode()));
}
}
throw new RuntimeException("Unable to get a response after retry.");
}
Expand Down

0 comments on commit 225fd58

Please sign in to comment.