Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.hubspot.singularity.s3.base.S3ArtifactChunkDownloader Maven / Gradle / Ivy
package com.hubspot.singularity.s3.base;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.slf4j.Logger;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.GetObjectRequest;
import com.amazonaws.services.s3.model.S3Object;
import com.google.common.collect.ImmutableMap;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.hubspot.deploy.S3Artifact;
import com.hubspot.mesos.JavaUtils;
import com.hubspot.singularity.runner.base.sentry.SingularityRunnerExceptionNotifier;
import com.hubspot.singularity.s3.base.config.SingularityS3Configuration;
public class S3ArtifactChunkDownloader implements Callable {
private final SingularityS3Configuration configuration;
private final AmazonS3 s3;
private final S3Artifact s3Artifact;
private final Path downloadTo;
private final int chunk;
private final long chunkSize;
private final long length;
private final Logger log;
private final SingularityRunnerExceptionNotifier exceptionNotifier;
private int retryNum;
public S3ArtifactChunkDownloader(SingularityS3Configuration configuration, Logger log, AmazonS3 s3, S3Artifact s3Artifact, Path downloadTo, int chunk, long chunkSize, long length, SingularityRunnerExceptionNotifier exceptionNotifier) {
this.configuration = configuration;
this.log = log;
this.s3 = s3;
this.s3Artifact = s3Artifact;
this.downloadTo = downloadTo;
this.chunk = chunk;
this.chunkSize = chunkSize;
this.length = length;
this.exceptionNotifier = exceptionNotifier;
}
@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 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();
}
}
private Callable createDownloader(final int retryNum) {
return new Callable() {
public Path call() throws Exception {
final Path chunkPath = (chunk == 0) ? downloadTo : Paths.get(downloadTo + "_" + chunk + "_" + retryNum);
chunkPath.toFile().deleteOnExit();
final long startTime = System.currentTimeMillis();
final long byteRangeStart = chunk * chunkSize;
final long byteRangeEnd = Math.min((chunk + 1) * chunkSize - 1, length);
log.info("Downloading {} - chunk {} (retry {}) ({}-{}) to {}", s3Artifact.getFilename(), chunk, retryNum, byteRangeStart, byteRangeEnd, chunkPath);
GetObjectRequest getObjectRequest = new GetObjectRequest(s3Artifact.getS3Bucket(), s3Artifact.getS3ObjectKey())
.withRange(byteRangeStart, byteRangeEnd);
S3Object fetchedObject = s3.getObject(getObjectRequest);
try (InputStream is = fetchedObject.getObjectContent()) {
Files.copy(is, chunkPath, StandardCopyOption.REPLACE_EXISTING);
}
log.info("Finished downloading chunk {} (retry {}) of {} ({} bytes) in {}", chunk, retryNum, s3Artifact.getFilename(), byteRangeEnd - byteRangeStart, JavaUtils.duration(startTime));
return chunkPath;
};
};
}
}