Skip to content

Commit 758f399

Browse files
coeuvrecopybara-github
authored andcommitted
Correctly detect ContentLengthMismatchException and retry.
The retry doesn't work if the ContentLengthMismatchException is wrapped in an IOException. PiperOrigin-RevId: 636107102 Change-Id: I721e0be325dfd7c4e8a3dd697f5d513f42bcb7aa
1 parent 2c0faf9 commit 758f399

File tree

2 files changed

+74
-11
lines changed

2 files changed

+74
-11
lines changed

src/main/java/com/google/devtools/build/lib/bazel/repository/downloader/DownloadManager.java

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,7 @@ private Path downloadInExecutor(
340340
throw new IOException(getRewriterBlockedAllUrlsMessage(originalUrls));
341341
}
342342

343-
for (int attempt = 0; attempt <= retries; ++attempt) {
343+
for (int attempt = 0; ; ++attempt) {
344344
try {
345345
downloader.download(
346346
rewrittenUrls,
@@ -353,12 +353,12 @@ private Path downloadInExecutor(
353353
clientEnv,
354354
type);
355355
break;
356-
} catch (ContentLengthMismatchException e) {
357-
if (attempt == retries) {
358-
throw e;
359-
}
360356
} catch (InterruptedIOException e) {
361357
throw new InterruptedException(e.getMessage());
358+
} catch (IOException e) {
359+
if (!shouldRetryDownload(e, attempt)) {
360+
throw e;
361+
}
362362
}
363363
}
364364

@@ -372,6 +372,24 @@ private Path downloadInExecutor(
372372
return destination;
373373
}
374374

375+
private boolean shouldRetryDownload(IOException e, int attempt) {
376+
if (attempt >= retries) {
377+
return false;
378+
}
379+
380+
if (e instanceof ContentLengthMismatchException) {
381+
return true;
382+
}
383+
384+
for (var suppressed : e.getSuppressed()) {
385+
if (suppressed instanceof ContentLengthMismatchException) {
386+
return true;
387+
}
388+
}
389+
390+
return false;
391+
}
392+
375393
/**
376394
* Downloads the contents of one URL and reads it into a byte array.
377395
*
@@ -447,8 +465,8 @@ public byte[] downloadAndReadOneUrlForBzlmod(
447465
}
448466

449467
HttpDownloader httpDownloader = new HttpDownloader();
450-
byte[] content = null;
451-
for (int attempt = 0; attempt <= retries; ++attempt) {
468+
byte[] content;
469+
for (int attempt = 0; ; ++attempt) {
452470
try {
453471
content =
454472
httpDownloader.downloadAndReadOneUrl(
@@ -458,12 +476,12 @@ public byte[] downloadAndReadOneUrlForBzlmod(
458476
eventHandler,
459477
clientEnv);
460478
break;
461-
} catch (ContentLengthMismatchException e) {
462-
if (attempt == retries) {
463-
throw e;
464-
}
465479
} catch (InterruptedIOException e) {
466480
throw new InterruptedException(e.getMessage());
481+
} catch (IOException e) {
482+
if (!shouldRetryDownload(e, attempt)) {
483+
throw e;
484+
}
467485
}
468486
}
469487
if (content == null) {

src/test/java/com/google/devtools/build/lib/bazel/repository/downloader/HttpDownloaderTest.java

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -713,4 +713,49 @@ public void download_contentLengthMismatch_retries() throws Exception {
713713
String content = new String(ByteStreams.toByteArray(result.getInputStream()), UTF_8);
714714
assertThat(content).isEqualTo("content");
715715
}
716+
717+
@Test
718+
public void download_contentLengthMismatchWithOtherErrors_retries() throws Exception {
719+
Downloader downloader = mock(Downloader.class);
720+
int retires = 5;
721+
DownloadManager downloadManager = new DownloadManager(repositoryCache, downloader);
722+
downloadManager.setRetries(retires);
723+
AtomicInteger times = new AtomicInteger(0);
724+
byte[] data = "content".getBytes(UTF_8);
725+
doAnswer(
726+
(Answer<Void>)
727+
invocationOnMock -> {
728+
if (times.getAndIncrement() < 3) {
729+
IOException e = new IOException();
730+
e.addSuppressed(new ContentLengthMismatchException(0, data.length));
731+
e.addSuppressed(new IOException());
732+
throw e;
733+
}
734+
Path output = invocationOnMock.getArgument(5, Path.class);
735+
try (OutputStream outputStream = output.getOutputStream()) {
736+
ByteStreams.copy(new ByteArrayInputStream(data), outputStream);
737+
}
738+
739+
return null;
740+
})
741+
.when(downloader)
742+
.download(any(), any(), any(), any(), any(), any(), any(), any(), any());
743+
744+
Path result =
745+
downloadManager.download(
746+
ImmutableList.of(new URL("http://localhost")),
747+
ImmutableMap.of(),
748+
ImmutableMap.of(),
749+
Optional.empty(),
750+
"testCanonicalId",
751+
Optional.empty(),
752+
fs.getPath(workingDir.newFile().getAbsolutePath()),
753+
eventHandler,
754+
ImmutableMap.of(),
755+
"testRepo");
756+
757+
assertThat(times.get()).isEqualTo(4);
758+
String content = new String(result.getInputStream().readAllBytes(), UTF_8);
759+
assertThat(content).isEqualTo("content");
760+
}
716761
}

0 commit comments

Comments
 (0)