Skip to content

Commit

Permalink
Merge pull request #42522 from Thevakumar-Luheerathan/fix-ballerina-l…
Browse files Browse the repository at this point in the history
…ang-iss-42431

Add retry support for CentralAPIClient
  • Loading branch information
azinneera authored May 10, 2024
2 parents 89f1a39 + bced9ae commit 740a149
Show file tree
Hide file tree
Showing 20 changed files with 570 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -465,7 +465,7 @@ private static void pullPackageFromRemote(String orgName, String packageName, St
settings.getProxy().password(),
getAccessTokenOfCLI(settings), settings.getCentral().getConnectTimeout(),
settings.getCentral().getReadTimeout(), settings.getCentral().getWriteTimeout(),
settings.getCentral().getCallTimeout());
settings.getCentral().getCallTimeout(), settings.getCentral().getMaxRetries());
try {
client.pullPackage(orgName, packageName, version, destination, supportedPlatform,
RepoUtils.getBallerinaVersion(), false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ private void deprecateInCentral(String packageInfo) {
settings.getProxy().password(),
getAccessTokenOfCLI(settings), settings.getCentral().getConnectTimeout(),
settings.getCentral().getReadTimeout(), settings.getCentral().getWriteTimeout(),
settings.getCentral().getCallTimeout());
settings.getCentral().getCallTimeout(), settings.getCentral().getMaxRetries());
client.deprecatePackage(packageValue, deprecationMsg,
JvmTarget.JAVA_17.code(),
RepoUtils.getBallerinaVersion(), this.undoFlag);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ public void execute() {
settings.getProxy().password(), getAccessTokenOfCLI(settings),
settings.getCentral().getConnectTimeout(),
settings.getCentral().getReadTimeout(), settings.getCentral().getWriteTimeout(),
settings.getCentral().getCallTimeout());
settings.getCentral().getCallTimeout(), settings.getCentral().getMaxRetries());
client.pullPackage(orgName, packageName, version, packagePathInBalaCache, supportedPlatform,
RepoUtils.getBallerinaVersion(), false);
if (version.equals(Names.EMPTY.getValue())) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ public void execute() {
settings.getProxy().password(), getAccessTokenOfCLI(settings),
settings.getCentral().getConnectTimeout(),
settings.getCentral().getReadTimeout(), settings.getCentral().getWriteTimeout(),
settings.getCentral().getCallTimeout());
settings.getCentral().getCallTimeout(), settings.getCentral().getMaxRetries());
if (balaPath == null) {
pushPackage(project, client);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,8 @@ private void searchInCentral(String query) {
settings.getCentral().getConnectTimeout(),
settings.getCentral().getReadTimeout(),
settings.getCentral().getWriteTimeout(),
settings.getCentral().getCallTimeout());
settings.getCentral().getCallTimeout(),
settings.getCentral().getMaxRetries());
boolean foundSearch = false;
String supportedPlatform = Arrays.stream(JvmTarget.values())
.map(target -> target.code())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,7 @@ private void pullToolFromCentral(String supportedPlatform, Path balaCacheDirPath
settings.getProxy().password(), getAccessTokenOfCLI(settings),
settings.getCentral().getConnectTimeout(),
settings.getCentral().getReadTimeout(), settings.getCentral().getWriteTimeout(),
settings.getCentral().getCallTimeout());
settings.getCentral().getCallTimeout(), settings.getCentral().getMaxRetries());
String[] toolInfo = client.pullTool(toolId, version, balaCacheDirPath, supportedPlatform,
RepoUtils.getBallerinaVersion(), false);
boolean isPulled = Boolean.parseBoolean(toolInfo[0]);
Expand Down Expand Up @@ -667,7 +667,7 @@ private void searchToolsInCentral(String keyword) {
settings.getProxy().password(), getAccessTokenOfCLI(settings),
settings.getCentral().getConnectTimeout(),
settings.getCentral().getReadTimeout(), settings.getCentral().getWriteTimeout(),
settings.getCentral().getCallTimeout());
settings.getCentral().getCallTimeout(), settings.getCentral().getMaxRetries());
boolean foundTools = false;
String supportedPlatform = Arrays.stream(JvmTarget.values())
.map(JvmTarget::code)
Expand Down Expand Up @@ -830,7 +830,7 @@ private String getLatestVersionForUpdateCommand(String supportedPlatforms, BalTo
settings.getProxy().password(), getAccessTokenOfCLI(settings),
settings.getCentral().getConnectTimeout(),
settings.getCentral().getReadTimeout(), settings.getCentral().getWriteTimeout(),
settings.getCentral().getCallTimeout());
settings.getCentral().getCallTimeout(), settings.getCentral().getMaxRetries());
List<String> versions = client.getPackageVersions(tool.org(), tool.name(), supportedPlatforms,
RepoUtils.getBallerinaVersion());
return getLatestVersion(versions, tool.version());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ private void pullToolFromCentral(String toolId, String version) throws CentralCl
settings.getProxy().password(), getAccessTokenOfCLI(settings),
settings.getCentral().getConnectTimeout(),
settings.getCentral().getReadTimeout(), settings.getCentral().getWriteTimeout(),
settings.getCentral().getCallTimeout());
settings.getCentral().getCallTimeout(), settings.getCentral().getMaxRetries());
String[] toolInfo = client.pullTool(toolId, version, balaCacheDirPath, supportedPlatform,
RepoUtils.getBallerinaVersion(), false);
boolean isPulled = Boolean.parseBoolean(toolInfo[0]);
Expand Down
1 change: 1 addition & 0 deletions cli/central-client/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ dependencies {
implementation 'com.squareup.okhttp3:okhttp'
implementation 'com.squareup.okio:okio'

testImplementation "com.squareup.okhttp3:mockwebserver:${mockWebserverVersion}"
testImplementation "org.mockito:mockito-core:${mockitoCoreVersion}"
testImplementation "org.mockito:mockito-testng:${mockitoTestNGVersion}"
testImplementation 'org.testng:testng'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import okhttp3.Call;
import okhttp3.Credentials;
import okhttp3.HttpUrl;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
Expand Down Expand Up @@ -145,6 +146,8 @@ public class CentralAPIClient {
private static final int DEFAULT_READ_TIMEOUT = 60;
private static final int DEFAULT_WRITE_TIMEOUT = 60;
private static final int DEFAULT_CALL_TIMEOUT = 0;
private static final int MAX_RETRY = 1;
public static final String CONNECTION_RESET = "Connection reset";

private final String baseUrl;
private final Proxy proxy;
Expand All @@ -157,6 +160,7 @@ public class CentralAPIClient {
private final int readTimeout;
private final int writeTimeout;
private final int callTimeout;
private final int maxRetries;

public CentralAPIClient(String baseUrl, Proxy proxy, String accessToken) {
this.outStream = System.out;
Expand All @@ -170,11 +174,28 @@ public CentralAPIClient(String baseUrl, Proxy proxy, String accessToken) {
this.readTimeout = DEFAULT_READ_TIMEOUT;
this.writeTimeout = DEFAULT_WRITE_TIMEOUT;
this.callTimeout = DEFAULT_CALL_TIMEOUT;
this.maxRetries = MAX_RETRY;
}

public CentralAPIClient(String baseUrl, Proxy proxy, String accessToken, boolean verboseEnabled, int maxRetries,
PrintStream outStream) {
this.outStream = outStream;
this.baseUrl = baseUrl;
this.proxy = proxy;
this.accessToken = accessToken;
this.verboseEnabled = verboseEnabled;
this.proxyUsername = "";
this.proxyPassword = "";
this.connectTimeout = DEFAULT_CONNECT_TIMEOUT;
this.readTimeout = DEFAULT_READ_TIMEOUT;
this.writeTimeout = DEFAULT_WRITE_TIMEOUT;
this.callTimeout = DEFAULT_CALL_TIMEOUT;
this.maxRetries = maxRetries;
}

public CentralAPIClient(String baseUrl, Proxy proxy, String proxyUsername, String proxyPassword,
String accessToken, int connectionTimeout, int readTimeout, int writeTimeout,
int callTimeout) {
int callTimeout, int maxRetries) {
this.outStream = System.out;
this.baseUrl = baseUrl;
this.proxy = proxy;
Expand All @@ -186,6 +207,7 @@ public CentralAPIClient(String baseUrl, Proxy proxy, String proxyUsername, Strin
this.readTimeout = readTimeout;
this.writeTimeout = writeTimeout;
this.callTimeout = callTimeout;
this.maxRetries = maxRetries;
}

/**
Expand Down Expand Up @@ -492,6 +514,31 @@ public void pushPackage(Path balaPath, String org, String name, String version,
* @throws CentralClientException Central Client exception.
*/
public void pullPackage(String org, String name, String version, Path packagePathInBalaCache,
String supportedPlatform, String ballerinaVersion, boolean isBuild)
throws CentralClientException {
int retryCount = 0;
while (retryCount <= this.maxRetries) {
try {
pullPackageInternal(org, name, version, packagePathInBalaCache, supportedPlatform, ballerinaVersion,
isBuild);
break;
} catch (CentralClientException centralClientException) {
if (centralClientException.getMessage().contains(CONNECTION_RESET) && retryCount < this.maxRetries) {
if (verboseEnabled) {
outStream.println("* Retrying to pull the package: " + org + "/" + name + ":" + version +
" due to: " + centralClientException.getMessage() + ". Retry attempt: "
+ (retryCount + 1));
outStream.println();
}
retryCount++;
continue;
}
throw centralClientException;
}
}
}

private void pullPackageInternal(String org, String name, String version, Path packagePathInBalaCache,
String supportedPlatform, String ballerinaVersion, boolean isBuild)
throws CentralClientException {
String resourceUrl = PACKAGE_PATH_PREFIX + org + SEPARATOR + name;
Expand Down Expand Up @@ -644,6 +691,31 @@ public void pullPackage(String org, String name, String version, Path packagePat
* @throws CentralClientException Central Client exception.
*/
public String[] pullTool(String toolId, String version, Path balaCacheDirPath, String supportedPlatform,
String ballerinaVersion, boolean isBuild) throws CentralClientException {
int retryCount = 0;
String[] result = new String[0];
while (retryCount <= this.maxRetries) {
try {
result = pullToolInternal(toolId, version, balaCacheDirPath, supportedPlatform, ballerinaVersion,
isBuild);
break;
} catch (CentralClientException centralClientException) {
if (centralClientException.getMessage().contains(CONNECTION_RESET) && retryCount < this.maxRetries) {
if (verboseEnabled) {
outStream.println("* Retrying to pull the tool: " + toolId + ":" + version + " due to: "
+ centralClientException.getMessage() + ". Retry attempt: " + (retryCount + 1));
outStream.println();
}
retryCount++;
continue;
}
throw centralClientException;
}
}
return result;
}

private String[] pullToolInternal(String toolId, String version, Path balaCacheDirPath, String supportedPlatform,
String ballerinaVersion, boolean isBuild) throws CentralClientException {
String resourceUrl = TOOL_PATH_PREFIX + toolId;
boolean enableOutputStream = Boolean
Expand Down Expand Up @@ -1524,6 +1596,7 @@ protected OkHttpClient getClient() {
.followRedirects(false)
.retryOnConnectionFailure(true)
.proxy(this.proxy)
.addInterceptor(new CustomRetryInterceptor(this.maxRetries))
.build();

if ((!(this.proxyUsername).isEmpty() && !(this.proxyPassword).isEmpty())) {
Expand Down Expand Up @@ -1851,4 +1924,52 @@ private void logRequestConnectVerbose(Request request, String resourceUrl) {
this.outStream.println(">");
}
}

class CustomRetryInterceptor implements Interceptor {
private final int maxRetries;
CustomRetryInterceptor(int maxRetry) {
this.maxRetries = maxRetry;
}

@Override
public Response intercept(Chain chain) throws IOException {
int retryCount = 0;
Request request = chain.request();
Response response = null;
while (retryCount <= maxRetries) {
response = chain.proceed(request);
if (response.code() < 500 || retryCount == maxRetries) {
return response;
}
retryCount++;
Optional<ResponseBody> body = Optional.ofNullable(response.body());
String responseBodyString = null;
if (body.isPresent()) {
responseBodyString = body.get().string();
}
logRetryVerbose(response, responseBodyString, request, retryCount);
response.close();
}
return response;
}

private void logRetryVerbose(Response response, String bodyContent, Request request, int retryCount) {
if (verboseEnabled) {
Optional<ResponseBody> body = Optional.ofNullable(response.body());
outStream.println("< HTTP " + response.code() + " " + response.message());
if (body.isPresent()) {
for (String headerName : response.headers().names()) {
outStream.println("> " + headerName + ": " + response.header(headerName));
}
outStream.println("< ");
if (bodyContent != null && !bodyContent.isEmpty()) {
outStream.println(bodyContent);
}
outStream.println("* Connection to host " + baseUrl + " left intact \n");
}
outStream.println("* Retrying request to " + request.url() + " due to " + response.code() +
" response code. Retry attempt: " + retryCount);
}
}
}
}
Loading

0 comments on commit 740a149

Please sign in to comment.