@Override
public Path call() throws Exception {
final long start = System.currentTimeMillis();
final ExecutorService chunkExecutorService = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setDaemon(true).setNameFormat("S3ArtifactDownloaderChunk-" + chunk + "-Thread-%d").build());
try {
while (retryNum <= configuration.getS3ChunkRetries()) {
final long timeout = System.currentTimeMillis();
final Future<Path> future = chunkExecutorService.submit(createDownloader(retryNum));
try {
return future.get(configuration.getS3ChunkDownloadTimeoutMillis(), TimeUnit.MILLISECONDS);
} catch (TimeoutException te) {
log.error("Chunk {} (retry {}) for {} timed out after {} - total duration {}", chunk, retryNum, s3Artifact.getFilename(), JavaUtils.duration(timeout), JavaUtils.duration(start));
future.cancel(true);
if (retryNum == configuration.getS3ChunkRetries()) {
exceptionNotifier.notify("Timeout downloading chunk", te, ImmutableMap.of("filename", s3Artifact.getFilename(), "chunk", Integer.toString(chunk), "retry", Integer.toString(retryNum)));
}
} catch (InterruptedException ie) {
log.warn("Chunk {} (retry {}) for {} interrupted", chunk, retryNum, s3Artifact.getFilename());
exceptionNotifier.notify("Interrupted during download", ie, ImmutableMap.of("filename", s3Artifact.getFilename(), "chunk", Integer.toString(chunk), "retry", Integer.toString(retryNum)));
} catch (Throwable t) {
log.error("Error while downloading chunk {} (retry {}) for {}", chunk, retryNum, s3Artifact.getFilename(), t);
exceptionNotifier.notify(String.format("Error downloading chunk (%s)", t.getMessage()), t, ImmutableMap.of("filename", s3Artifact.getFilename(), "chunk", Integer.toString(chunk), "retry", Integer.toString(retryNum)));
}
retryNum++;
}
throw new IllegalStateException(String.format("Chunk %s for %s failed to download after %s tries", chunk, s3Artifact.getFilename(), retryNum + 1));
} finally {
chunkExecutorService.shutdownNow();
}
}