Skip to content

S3 TransferListener Progress percent not work properly when uploading byte arrays  #4114

Closed as not planned
@JmKanmo

Description

@JmKanmo

Describe the bug

0.0 => 100.0% => (4min 25sec later) => Transfer complete!

It didn't show process percent gradually.

source code

 StopWatch stopWatch = new StopWatch();

        final String WHATAP_DESTINATION_KEY = "5/myhome.com/1.0/howlong_2gb_window_1111111gngngngn_file";

        File file = new File("/Users/junmokang/whatap/files/test_files/test10.js.map");
        byte[] originBytes = IoUtils.toByteArray(new FileInputStream(file));

        S3TransferManager transferManager = S3TransferManager.builder()
                .s3Client(S3AsyncClient.crtBuilder()
                        .region(Region.US_EAST_1)
                        .targetThroughputInGbps(30.0)
                        .minimumPartSizeInBytes(30 * 1024 * 1024L)
                        .credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create(WHATAP_AWS_ACCESS_KEY_ID, WHATAP_AWS_SECRET_ACCESS_KEY)))
                        .httpConfiguration(a -> {
                            NettyNioAsyncHttpClient.builder()
                                    .maxConcurrency(500)
                                    .maxPendingConnectionAcquires(10000)
                                    .writeTimeout(Duration.ofSeconds(180))
                                    .connectionMaxIdleTime(Duration.ofSeconds(300))
                                    .connectionTimeout(Duration.ofSeconds(180))
                                    .connectionAcquisitionTimeout(Duration.ofSeconds(180))
                                    .readTimeout(Duration.ofSeconds(180)).build();
                        })
                        .build())
                .build();

        stopWatch.start();

        UploadRequest uploadRequest = UploadRequest.builder()
                .putObjectRequest(b -> b.bucket(WHATAP_AWS_BUCKET_NAME).key(WHATAP_DESTINATION_KEY))
                .addTransferListener(LoggingTransferListener.create(1))
                .requestBody(AsyncRequestBody.fromBytes(originBytes))
                .build();

        // Wait for the transfer to complete
        CompletedUpload completedUpload = transferManager.upload(uploadRequest).completionFuture().whenComplete((result, e) -> {
            if (e != null) {
                throw new RuntimeException("Failed to s3 upload file, e = " + e);
            }
        }).join();

        stopWatch.stop();
        String result = completedUpload.response().eTag();
        System.out.println("upload completed, interval: " + stopWatch.getTime() + ", result[eTag]:" + result);

I impleneted TransferListener classs. (S3PrintStackListener)

import software.amazon.awssdk.transfer.s3.progress.LoggingTransferListener;
import software.amazon.awssdk.transfer.s3.progress.TransferListener;
import software.amazon.awssdk.utils.Logger;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.concurrent.atomic.AtomicInteger;

import static software.amazon.awssdk.utils.StringUtils.repeat;

public class S3PrintStackListener implements TransferListener {
    private static final int DEFAULT_MAX_TICKS = 20;
    private final S3PrintStackListener.ProgressBar progressBar;

    public S3PrintStackListener(int maxTicks) {
        progressBar = new S3PrintStackListener.ProgressBar(maxTicks);
    }

    @Override
    public void transferInitiated(Context.TransferInitiated context) {
        System.out.println("Transfer initiated...");
        context.progressSnapshot().ratioTransferred().ifPresent(progressBar::update);
    }

    @Override
    public void bytesTransferred(Context.BytesTransferred context) {
        context.progressSnapshot().ratioTransferred().ifPresent(progressBar::update);
    }

    @Override
    public void transferComplete(Context.TransferComplete context) {
        context.progressSnapshot().ratioTransferred().ifPresent(progressBar::update);
        System.out.println("Transfer complete!");
    }

    @Override
    public void transferFailed(Context.TransferFailed context) {
        System.out.println("Transfer failed." + context.exception());
    }

    private static class ProgressBar {
        private final int maxTicks;
        private final AtomicInteger prevTicks = new AtomicInteger(-1);

        ProgressBar(int maxTicks) {
            this.maxTicks = maxTicks;
        }

        void update(double ratio) {
            int ticks = (int) Math.floor(ratio * maxTicks);
            if (prevTicks.getAndSet(ticks) != ticks) {
                System.out.println(String.format("|%s%s| %s",
                        repeat("=", ticks),
                        repeat(" ", maxTicks - ticks),
                        round(ratio * 100, 1) + "%"));
            }
        }

        private static double round(double value, int places) {
            BigDecimal bd = BigDecimal.valueOf(value);
            bd = bd.setScale(places, RoundingMode.FLOOR);
            return bd.doubleValue();
        }
    }
}

capture
스크린샷 2023-06-01 오후 4 15 48

Expected Behavior

Below code is s3 file download. It work properly.

        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        S3TransferManager transferManager = S3TransferManager.builder()
                .s3Client(S3AsyncClient.crtBuilder()
                        .region(Region.US_EAST_1)
                        .targetThroughputInGbps(30.0)
                        .minimumPartSizeInBytes(30 * 1024 * 1024L)
                        .credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create(WHATAP_AWS_ACCESS_KEY_ID, WHATAP_AWS_SECRET_ACCESS_KEY)))
                        .httpConfiguration(a -> {
                            NettyNioAsyncHttpClient.builder()
                                    .maxConcurrency(500)
                                    .maxPendingConnectionAcquires(10000)
                                    .writeTimeout(Duration.ofSeconds(180))
                                    .connectionMaxIdleTime(Duration.ofSeconds(300))
                                    .connectionTimeout(Duration.ofSeconds(180))
                                    .connectionAcquisitionTimeout(Duration.ofSeconds(180))
                                    .readTimeout(Duration.ofSeconds(180)).build();
                        })
                        .build())
                .build();

        // Initiate the transfer
        Download<ResponseBytes<GetObjectResponse>> download =
                transferManager.download(DownloadRequest.builder()
                        .getObjectRequest(req -> req.bucket(WHATAP_AWS_BUCKET_NAME).key("5/myhome.com/1.0/howlong_2gb_window_monitor_file"))
                        .responseTransformer(AsyncResponseTransformer.toBytes())
                        .addTransferListener(new S3PrintStackListener(20))
                        .build());
        // Wait for the transfer to complete
        byte[] bytes = download.completionFuture().get().result().asByteArray();
        Assertions.assertNotNull(bytes);
        Assertions.assertTrue(bytes.length > 0);
        stopWatch.stop();
        System.out.println("download completed, interval: " + stopWatch.getTime());

The progress percent image is below
스크린샷 2023-06-01 오후 4 24 24

Current Behavior

I think this problem no needed include log

Reproduction Steps

Just watch console

@Test
    public void uploadPutObjectRequest() throws Exception {
        StopWatch stopWatch = new StopWatch();

        final String WHATAP_DESTINATION_KEY = "5/myhome.com/1.0/howlong_2gb_window_1111111gngngngn_file";

        File file = new File("/Users/junmokang/whatap/files/test_files/test10.js.map");
        byte[] originBytes = IoUtils.toByteArray(new FileInputStream(file));

        S3TransferManager transferManager = S3TransferManager.builder()
                .s3Client(S3AsyncClient.crtBuilder()
                        .region(Region.US_EAST_1)
                        .targetThroughputInGbps(30.0)
                        .minimumPartSizeInBytes(30 * 1024 * 1024L)
                        .credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create(WHATAP_AWS_ACCESS_KEY_ID, WHATAP_AWS_SECRET_ACCESS_KEY)))
                        .httpConfiguration(a -> {
                            NettyNioAsyncHttpClient.builder()
                                    .maxConcurrency(500)
                                    .maxPendingConnectionAcquires(10000)
                                    .writeTimeout(Duration.ofSeconds(180))
                                    .connectionMaxIdleTime(Duration.ofSeconds(300))
                                    .connectionTimeout(Duration.ofSeconds(180))
                                    .connectionAcquisitionTimeout(Duration.ofSeconds(180))
                                    .readTimeout(Duration.ofSeconds(180)).build();
                        })
                        .build())
                .build();

        stopWatch.start();

        UploadRequest uploadRequest = UploadRequest.builder()
                .putObjectRequest(b -> b.bucket(WHATAP_AWS_BUCKET_NAME).key(WHATAP_DESTINATION_KEY))
                .addTransferListener(LoggingTransferListener.create(1))
                .requestBody(AsyncRequestBody.fromBytes(originBytes))
                .build();

        // Wait for the transfer to complete
        CompletedUpload completedUpload = transferManager.upload(uploadRequest).completionFuture().whenComplete((result, e) -> {
            if (e != null) {
                throw new RuntimeException("Failed to s3 upload file, e = " + e);
            }
        }).join();

        stopWatch.stop();
        String result = completedUpload.response().eTag();
        System.out.println("upload completed, interval: " + stopWatch.getTime() + ", result[eTag]:" + result);
    }

Possible Solution

No response

Additional Information/Context

No response

AWS Java SDK version used

software.amazon.awssdk 2.20.76, software.amazon.awssdk.s3-transfer-manager 2.20.75, software.amazon.awssdk.crt.aws-crt 0.21.17

JDK version used

OpenJDK Runtime Environment AdoptOpenJDK-11.0.11+9 (build 11.0.11+9)

Operating System and version

MacBookPro18

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugThis issue is a bug.p2This is a standard priority issuetransfer-manager

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions