Skip to content

Commit 4d46146

Browse files
authored
added additional retry logic for retrieving Oracle patches (#347)
1 parent 091c02b commit 4d46146

File tree

4 files changed

+103
-18
lines changed

4 files changed

+103
-18
lines changed

imagetool/src/main/java/com/oracle/weblogic/imagetool/aru/AruUtil.java

Lines changed: 91 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import java.io.File;
77
import java.io.IOException;
8+
import java.net.UnknownHostException;
89
import java.util.ArrayList;
910
import java.util.Collections;
1011
import java.util.List;
@@ -36,6 +37,42 @@ public class AruUtil {
3637

3738
private static final String BUG_SEARCH_URL = ARU_REST_URL + "/search?bug=%s";
3839

40+
private static int REST_RETRIES = 10;
41+
private static int REST_INTERVAL = 500;
42+
43+
static {
44+
// static block to parst environment variable overrides for REST call defaults
45+
final String retriesEnvVar = "WLSIMG_REST_RETRY_MAX";
46+
final String retriesString = System.getenv(retriesEnvVar);
47+
try {
48+
if (retriesString != null) {
49+
REST_RETRIES = Integer.parseInt(retriesString);
50+
if (REST_RETRIES < 1) {
51+
REST_RETRIES = 10;
52+
logger.severe("IMG-0109", retriesEnvVar, retriesString, 1, REST_RETRIES);
53+
}
54+
logger.fine("Retry max set to {0}", REST_RETRIES);
55+
}
56+
} catch (NumberFormatException nfe) {
57+
logger.warning("IMG-0108", retriesEnvVar, retriesString);
58+
}
59+
60+
final String waitEnvVar = "WLSIMG_REST_RETRY_INTERVAL";
61+
final String waitString = System.getenv(waitEnvVar);
62+
try {
63+
if (waitString != null) {
64+
REST_INTERVAL = Integer.parseInt(waitString);
65+
if (REST_INTERVAL < 0) {
66+
REST_INTERVAL = 500;
67+
logger.severe("IMG-0109", waitEnvVar, waitString, 0, REST_INTERVAL);
68+
}
69+
logger.fine("Retry interval set to {0}", REST_INTERVAL);
70+
}
71+
} catch (NumberFormatException nfe) {
72+
logger.warning("IMG-0108", waitEnvVar, waitString);
73+
}
74+
}
75+
3976
/**
4077
* Get ARU HTTP helper instance.
4178
* @return ARU helper.
@@ -98,13 +135,14 @@ List<AruPatch> getLatestPsu(AruProduct product, String version, String userId, S
98135
try {
99136
logger.info("IMG-0019", product.description());
100137
String releaseNumber = getReleaseNumber(product, version, userId, password);
101-
Document aruRecommendations = getRecommendedPatchesMetadata(product, releaseNumber, userId, password);
138+
Document aruRecommendations = retry(
139+
() -> getRecommendedPatchesMetadata(product, releaseNumber, userId, password));
102140
logger.exiting();
103141
return AruPatch.removeStackPatchBundle(AruPatch.getPatches(aruRecommendations, "[./psu_bundle]"));
104142
} catch (NoPatchesFoundException | ReleaseNotFoundException ex) {
105143
logger.exiting();
106144
return Collections.emptyList();
107-
} catch (IOException | XPathExpressionException e) {
145+
} catch (RetryFailedException | XPathExpressionException e) {
108146
throw logger.throwing(
109147
new AruException(Utils.getMessage("IMG-0032", product.description(), version), e));
110148
}
@@ -149,7 +187,8 @@ List<AruPatch> getRecommendedPatches(AruProduct product, String version, String
149187
try {
150188
logger.info("IMG-0067", product.description());
151189
String releaseNumber = getReleaseNumber(product, version, userId, password);
152-
Document aruRecommendations = getRecommendedPatchesMetadata(product, releaseNumber, userId, password);
190+
Document aruRecommendations = retry(
191+
() -> getRecommendedPatchesMetadata(product, releaseNumber, userId, password));
153192
List<AruPatch> patches = AruPatch.removeStackPatchBundle(AruPatch.getPatches(aruRecommendations));
154193
String psuVersion = getPsuVersion(patches);
155194
if (!Utils.isEmptyString(psuVersion)) {
@@ -159,8 +198,10 @@ List<AruPatch> getRecommendedPatches(AruProduct product, String version, String
159198
// get release number for PSU
160199
String psuReleaseNumber = getReleaseNumber(product, psuVersion, userId, password);
161200
// get recommended patches for PSU release (Overlay patches are only recommended on the PSU release)
162-
Document psuRecommendation = getRecommendedPatchesMetadata(product, psuReleaseNumber, userId, password);
163-
patches = AruPatch.removeStackPatchBundle(AruPatch.getPatches(psuRecommendation));
201+
Document psuOverrides = retry(
202+
() -> getRecommendedPatchesMetadata(product, psuReleaseNumber, userId, password));
203+
204+
patches = AruPatch.removeStackPatchBundle(AruPatch.getPatches(psuOverrides));
164205
}
165206
patches.forEach(p -> logger.info("IMG-0068", product.description(), p.patchId(), p.description()));
166207
logger.exiting(patches);
@@ -170,7 +211,7 @@ List<AruPatch> getRecommendedPatches(AruProduct product, String version, String
170211
} catch (NoPatchesFoundException npf) {
171212
logger.info("IMG-0069", product.description(), version);
172213
return Collections.emptyList();
173-
} catch (IOException | XPathExpressionException e) {
214+
} catch (RetryFailedException | XPathExpressionException e) {
174215
throw new AruException(Utils.getMessage("IMG-0070", product.description(), version), e);
175216
}
176217
}
@@ -275,16 +316,15 @@ Document getAllReleases(String userId, String password) throws AruException {
275316
if (allReleasesDocument == null) {
276317
logger.fine("Getting all releases document from ARU...");
277318
try {
278-
Document response = HttpUtil.getXMLContent(REL_URL, userId, password);
279-
verifyResponse(response);
280-
allReleasesDocument = response;
281-
} catch (IOException | AruException | XPathExpressionException ex) {
282-
throw new AruException(Utils.getMessage("IMG-0081"), ex);
319+
allReleasesDocument = retry(() -> getAndVerify(REL_URL, userId, password));
320+
} catch (RetryFailedException e) {
321+
throw new AruException(Utils.getMessage("IMG-0081"));
283322
}
284323
}
285324
return allReleasesDocument;
286325
}
287326

327+
// could be private, but leaving as protected for unit testing
288328
Document getRecommendedPatchesMetadata(AruProduct product, String releaseNumber, String userId, String password)
289329
throws IOException, AruException, XPathExpressionException {
290330

@@ -356,7 +396,13 @@ public static boolean checkCredentials(String username, String password) {
356396
return aruHttpHelper.success();
357397
}
358398

359-
void verifyResponse(Document response) throws AruException, XPathExpressionException {
399+
private Document getAndVerify(String url, String userId, String password)
400+
throws IOException, XPathExpressionException, AruException {
401+
Document response = HttpUtil.getXMLContent(url, userId, password);
402+
return verifyResponse(response);
403+
}
404+
405+
private Document verifyResponse(Document response) throws AruException, XPathExpressionException {
360406
NodeList nodeList = XPathUtil.nodelist(response, "/results/error");
361407
if (nodeList.getLength() > 0) {
362408
String errorMessage = XPathUtil.string(response, "/results/error/message");
@@ -371,6 +417,7 @@ void verifyResponse(Document response) throws AruException, XPathExpressionExcep
371417
logger.throwing(error);
372418
throw error;
373419
}
420+
return response;
374421
}
375422

376423
/**
@@ -393,13 +440,14 @@ public List<AruPatch> getPatches(String bugNumber, String userId, String passwor
393440

394441
String url = String.format(BUG_SEARCH_URL, bugNumber);
395442
logger.info("IMG-0063", bugNumber);
396-
Document response = HttpUtil.getXMLContent(url, userId, password);
397443
try {
398-
verifyResponse(response);
444+
Document response = retry(() -> getAndVerify(url, userId, password));
445+
return AruPatch.getPatches(response);
399446
} catch (NoPatchesFoundException patchEx) {
400447
throw new NoPatchesFoundException(Utils.getMessage("IMG-0086", bugNumber), patchEx);
448+
} catch (RetryFailedException retryEx) {
449+
throw new AruException(Utils.getMessage("IMG-0110", retryEx));
401450
}
402-
return AruPatch.getPatches(response);
403451
}
404452

405453
/**
@@ -426,13 +474,39 @@ public String downloadAruPatch(AruPatch aruPatch, String targetDir, String usern
426474
.socketTimeout(30000))
427475
.saveContent(new File(filename));
428476
} catch (Exception ex) {
429-
String message = String.format("Failed to download and save file %s from %s: %s", filename,
430-
aruPatch.downloadUrl(), ex.getLocalizedMessage());
477+
String message = Utils.getMessage("IMG-0107", filename, aruPatch.downloadUrl(), ex.getLocalizedMessage());
431478
logger.severe(message);
432479
throw new IOException(message, ex);
433480
}
434481
logger.exiting(filename);
435482
return filename;
436483
}
484+
485+
private interface CallToRetry {
486+
Document process() throws IOException, XPathExpressionException, AruException;
487+
}
488+
489+
// create an environment variable that can override the tries count (undocumented)
490+
private static Document retry(CallToRetry call) throws AruException, RetryFailedException {
491+
for (int i = 0; i < REST_RETRIES; i++) {
492+
try {
493+
return call.process();
494+
} catch (UnknownHostException e) {
495+
throw new AruException(e.getLocalizedMessage(), e);
496+
} catch (IOException | XPathExpressionException e) {
497+
logger.info("IMG-0106", e.getMessage(), (i + 1), REST_RETRIES);
498+
}
499+
try {
500+
if (REST_INTERVAL > 0) {
501+
logger.finer("Waiting {0} ms before retry...", REST_INTERVAL);
502+
Thread.sleep(REST_INTERVAL);
503+
}
504+
} catch (InterruptedException wakeAndAbort) {
505+
break;
506+
}
507+
}
508+
// When all retries are exhausted, raise an ARU exception to exit the process (give up)
509+
throw logger.throwing(new RetryFailedException());
510+
}
437511
}
438512

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Copyright (c) 2022, Oracle and/or its affiliates.
2+
// Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
3+
4+
package com.oracle.weblogic.imagetool.aru;
5+
6+
public class RetryFailedException extends Exception {
7+
}

imagetool/src/main/resources/ImageTool.properties

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,3 +104,8 @@ IMG-0102=WDT {0} file [[brightred: {1}]] could not be found.
104104
IMG-0103=wdtVersion cannot be none, a valid version from the Image Tool cache is required.
105105
IMG-0104=You must provide at least one of: a WDT installer file, a WDT model file, a WDT variable file, or a WDT archive file.
106106
IMG-0105=Installer version cannot use keyword of 'none'.
107+
IMG-0106=Failed to get response from patches server, {0}, retrying [{1}/{2}]
108+
IMG-0107=Failed to download and save file {0} from {1}: {2}
109+
IMG-0108=Environment variable {0}=`{1}` is not an integer and will be ignored.
110+
IMG-0109=Invalid value found in {0}. {1} < {2}. Using default value: {3}.
111+
IMG-0110=Retries exhausted, unable to obtain patch information from Oracle

imagetool/src/test/java/com/oracle/weblogic/imagetool/aru/AruUtilTest.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@ Document getRecommendedPatchesMetadata(AruProduct product, String releaseNumber,
7777
e.printStackTrace();
7878
throw new RuntimeException("failed to load resources XML", e);
7979
}
80-
verifyResponse(result);
8180
return result;
8281
}
8382

0 commit comments

Comments
 (0)