amazon-s3awss3transfermanager

Too many open processes when using AWS S3 TransferManager with MultipartUpload and S3ProgressListener for ResumableTransfer


We have implemented the AWS TransferManager with MultipartUpload and ResumableTransfer for file uploads.

Implemented the solution as per the below:
https://aws.amazon.com/blogs/developer/pausing-and-resuming-transfers-using-transfer-manager/ https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/examples-s3-transfermanager.html https://aws.amazon.com/blogs/mobile/pause-and-resume-amazon-s3-transfers-using-the-aws-mobile-sdk-for-android/

The process count was well under control when uploading file without the MultipartUpload and ResumableTransfer, but started increasing exponentially once we implemented the above-said approach.

SampleCode Below:

  try {
        AmazonS3 s3client = s3ClientFactory.createClient();
        xferManager = TransferManagerBuilder.standard()
                .withS3Client(s3client)
                .withMinimumUploadPartSize(6291456L) //6 * 1024 * 1024(long) (represents 6MB)
                .withMultipartUploadThreshold(6291456L) //6 * 1024 * 1024(long) (represents 6MB)
                .withExecutorFactory(() -> Executors.newFixedThreadPool(3))
                .build();
        String resumableTargetFile ="/path/to/resumableTargetFile";

        Upload upload = xferManager.upload(putRequest, new S3ProgressListener() {
            ExecutorService executor = Executors.newFixedThreadPool(1);

            @Override
            public void progressChanged(ProgressEvent progressEvent) {
                double pct = progressEvent.getBytesTransferred() * 100.0 / progressEvent.getBytes();
                LOGGER.info("Upload status for file - " + fileName + " is: " + Double.toString(pct) + "%");

                switch (progressEvent.getEventType()) {
                    case TRANSFER_STARTED_EVENT:
                        LOGGER.info("Started uploading file {} to S3", fileName);
                        break;
                    case TRANSFER_COMPLETED_EVENT:
                        LOGGER.info("Completed uploading file {} to S3", fileName);
                        break;
                    case TRANSFER_CANCELED_EVENT:
                        LOGGER.warn("Upload of file {} to S3 was aborted", fileName);
                        break;
                    case TRANSFER_FAILED_EVENT:
                        LOGGER.error("Failed uploading file {} to S3", fileName);
                        break;
                    default:
                        break;
                }
            }

            @Override
            public void onPersistableTransfer(final PersistableTransfer persistableTransfer) {
                executor.submit(() -> {
                    saveTransferState(persistableTransfer, resumableTargetFile);
                });
            }
        });

        UploadResult uploadResult = upload.waitForUploadResult();
        streamMD5 = uploadResult.getETag();

        if (upload.isDone()) {
            LOGGER.info("File {} uploaded successfully to S3 bucket {}",fileNameKey, bucketName);
        }
} catch (AmazonServiceException ase) {
    // The call was transmitted successfully, but Amazon S3 couldn't process
    // it, so it returned an error response.
    LOGGER.error("AmazonServiceException occurred: " + ase.getMessage());
} catch (SdkClientException sdce) {
    // Amazon S3 couldn't be contacted for a response, or the client
    // couldn't parse the response from Amazon S3.
    LOGGER.error("SdkClientException occurred: " + sdce.getMessage());
} catch (AmazonClientException ace) {
    LOGGER.error("AWS Exception occurred: " + ace.getMessage());
} catch (Exception e) {
    LOGGER.error("Exception occurred during files processing: " + e.getMessage());
} finally {
    xferManager.shutdownNow(true);
    return streamMD5;
}

Looking to see if anyone has faced a similar issue and any inputs regarding this issue


Solution

  • Although as per AWS documentation, closing the TransferManager with TransferManager.shutdownNow(true) should close the TransferManager and the related child objects, we found that the ExecutorService spawned within the S3ProgressListener used for the ResumableTransfer was never getting closed upon closing the TransferManager.

    Once we closed the executor explicitly by calling executor.shutdown(), the issue with the open processes going up exponentially was addressed