Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create ProgressUpdater class to expose methods to invoke listeners to update request status #4861

Merged
merged 35 commits into from
Feb 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
588b102
Adding interfaces for Progress Listener and state capturing Progress …
anirudh9391 Dec 4, 2023
da26d3e
Modified Indentation
anirudh9391 Dec 5, 2023
99febb6
Added new change script
anirudh9391 Dec 5, 2023
7e70224
Revert "Added new change script"
anirudh9391 Dec 5, 2023
5e9057e
Added new change script
anirudh9391 Dec 5, 2023
e607d6c
Moved ProgressSnapshot to its own folder
anirudh9391 Dec 5, 2023
3d26526
Added sdkResponse to Progress Snapshot
anirudh9391 Dec 5, 2023
48a6617
Change totalTransferSize to totalBytes
anirudh9391 Dec 5, 2023
b096765
Modify return types of start and elapsedTime to Optional
anirudh9391 Dec 6, 2023
b558e6b
Progress Listener Interface definition
anirudh9391 Dec 8, 2023
07f2bfb
Address PR comments on Progress Listener
anirudh9391 Dec 8, 2023
d2a3253
Fix checkstyle issues
anirudh9391 Dec 11, 2023
eaf9470
Fix checkstyle issues
anirudh9391 Dec 11, 2023
276fb70
Implement Default Progress Snapshot
anirudh9391 Dec 14, 2023
7b24093
Revert "Implement Default Progress Snapshot"
anirudh9391 Dec 14, 2023
a943002
Revert "Revert "Implement Default Progress Snapshot""
anirudh9391 Dec 14, 2023
1d56ce2
Remove changes to pom
anirudh9391 Dec 14, 2023
7c1978b
Merge branch 'feature/anirudkr-progress-listener' into dev/progress-l…
anirudh9391 Dec 14, 2023
2e66a9a
Add parameterized unit tests
anirudh9391 Dec 20, 2023
3ffbca2
fix failing tests
anirudh9391 Dec 20, 2023
2dfdef7
Defined ProgressListener invoker methods, along with success and fail…
anirudh9391 Dec 27, 2023
713f6c1
Merge branch 'feature/anirudkr-progress-listener' into dev/progress-l…
anirudh9391 Dec 27, 2023
ba7b059
Address PR comments
anirudh9391 Jan 3, 2024
dbdd27d
Remove SDK Preview API annotations
anirudh9391 Jan 4, 2024
29259df
Fixed a typo with error logging
anirudh9391 Jan 4, 2024
16e06b7
Rectify typo in adding listeners to RequestOverrideConfiguration and …
anirudh9391 Jan 9, 2024
54caa47
Added Progress Updater Class to invoke listener methods
anirudh9391 Jan 29, 2024
ef05f6b
Merge branch 'feature/anirudkr-progress-listener' into dev/progress-l…
anirudh9391 Jan 30, 2024
631f674
ProgressUpdater class
anirudh9391 Jan 31, 2024
700bd5e
Define ProgressUpdater and LoggingProgressListener
anirudh9391 Feb 1, 2024
06f811b
Added ProgressUpdater into ExecutionContext and removed asynchronous …
anirudh9391 Feb 13, 2024
3faf34e
Fixed checkstyle issues
anirudh9391 Feb 13, 2024
8946bc2
Merge branch 'feature/anirudkr-progress-listener' into dev/progress-l…
anirudh9391 Feb 13, 2024
8f18496
Merged from master
anirudh9391 Feb 13, 2024
6eacf65
Added tests for attemptFailureResponseBytesReceived
anirudh9391 Feb 14, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ protected RequestOverrideConfiguration(Builder<?> builder) {
this.endpointProvider = builder.endpointProvider();
this.compressionConfiguration = builder.compressionConfiguration();
this.plugins = Collections.unmodifiableList(new ArrayList<>(builder.plugins()));
this.progressListeners = Collections.unmodifiableList(new ArrayList<>());
this.progressListeners = Collections.unmodifiableList(new ArrayList<>(builder.progressListeners()));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@

package software.amazon.awssdk.core.http;

import java.util.Optional;
import software.amazon.awssdk.annotations.NotThreadSafe;
import software.amazon.awssdk.annotations.SdkProtectedApi;
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
import software.amazon.awssdk.core.interceptor.ExecutionInterceptorChain;
import software.amazon.awssdk.core.interceptor.InterceptorContext;
import software.amazon.awssdk.core.internal.progress.listener.ProgressUpdater;
import software.amazon.awssdk.core.signer.Signer;
import software.amazon.awssdk.metrics.MetricCollector;
import software.amazon.awssdk.utils.builder.CopyableBuilder;
Expand All @@ -36,13 +38,15 @@ public final class ExecutionContext implements ToCopyableBuilder<ExecutionContex
private final ExecutionInterceptorChain interceptorChain;
private final ExecutionAttributes executionAttributes;
private final MetricCollector metricCollector;
private final ProgressUpdater progressUpdater;

private ExecutionContext(final Builder builder) {
this.signer = builder.signer;
this.interceptorContext = builder.interceptorContext;
this.interceptorChain = builder.interceptorChain;
this.executionAttributes = builder.executionAttributes;
this.metricCollector = builder.metricCollector;
this.progressUpdater = builder.progressUpdater;
}

public static ExecutionContext.Builder builder() {
Expand Down Expand Up @@ -76,6 +80,10 @@ public MetricCollector metricCollector() {
return metricCollector;
}

public Optional<ProgressUpdater> progressUpdater() {
return progressUpdater != null ? Optional.of(progressUpdater) : Optional.empty();
}

@Override
public Builder toBuilder() {
return new Builder(this);
Expand All @@ -87,6 +95,7 @@ public static class Builder implements CopyableBuilder<Builder, ExecutionContext
private ExecutionAttributes executionAttributes;
private Signer signer;
private MetricCollector metricCollector;
private ProgressUpdater progressUpdater;

private Builder() {
}
Expand All @@ -97,6 +106,7 @@ private Builder(ExecutionContext executionContext) {
this.interceptorChain = executionContext.interceptorChain;
this.executionAttributes = executionContext.executionAttributes;
this.metricCollector = executionContext.metricCollector;
this.progressUpdater = executionContext.progressUpdater;
}

public Builder interceptorContext(InterceptorContext interceptorContext) {
Expand Down Expand Up @@ -124,6 +134,11 @@ public Builder metricCollector(MetricCollector metricCollector) {
return this;
}

public Builder progressUpdater(ProgressUpdater progressUpdater) {
this.progressUpdater = progressUpdater;
return this;
}

@Override
public ExecutionContext build() {
return new ExecutionContext(this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import software.amazon.awssdk.core.progress.listener.ProgressListener;
import software.amazon.awssdk.core.progress.snapshot.ProgressSnapshot;
import software.amazon.awssdk.http.SdkHttpRequest;
import software.amazon.awssdk.http.SdkHttpResponse;
import software.amazon.awssdk.utils.ToString;
import software.amazon.awssdk.utils.Validate;
import software.amazon.awssdk.utils.builder.CopyableBuilder;
Expand Down Expand Up @@ -91,6 +92,16 @@ public String toString() {
.build();
}

@Override
public SdkHttpResponse httpResponse() {
return progressListenerContext.httpResponse();
}

@Override
public ProgressSnapshot downloadProgressSnapshot() {
return progressListenerContext.downloadProgressSnapshot();
}

public static final class Builder implements CopyableBuilder<Builder, ProgressListenerFailedContext> {
private ProgressListenerContext progressListenerContext;
private Throwable exception;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,24 @@
import software.amazon.awssdk.annotations.SdkInternalApi;
import software.amazon.awssdk.annotations.ThreadSafe;
import software.amazon.awssdk.core.internal.progress.snapshot.DefaultProgressSnapshot;
import software.amazon.awssdk.core.progress.listener.SdkRequestProgress;
import software.amazon.awssdk.core.progress.listener.SdkExchangeProgress;
import software.amazon.awssdk.core.progress.snapshot.ProgressSnapshot;

/**
* An SDK-internal implementation of {@link SdkRequestProgress}. This implementation acts as a thin wrapper around {@link
* An SDK-internal implementation of {@link SdkExchangeProgress}. This implementation acts as a thin wrapper around {@link
* AtomicReference}, where calls to get the latest {@link #progressSnapshot()} simply return the latest reference, while {@link
* ProgressUpdater} is responsible for continuously updating the latest reference.
*
* @see SdkRequestProgress
* @see SdkExchangeProgress
*/
@Mutable
@ThreadSafe
@SdkInternalApi
public class DefaultSdkRequestProgress implements SdkRequestProgress {
public class DefaultSdkExchangeProgress implements SdkExchangeProgress {

private final AtomicReference<ProgressSnapshot> snapshot;

public DefaultSdkRequestProgress(ProgressSnapshot snapshot) {
public DefaultSdkExchangeProgress(ProgressSnapshot snapshot) {
this.snapshot = new AtomicReference<>(snapshot);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

package software.amazon.awssdk.core.internal.progress.listener;

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

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.concurrent.atomic.AtomicInteger;
import software.amazon.awssdk.annotations.SdkPublicApi;
import software.amazon.awssdk.core.progress.listener.ProgressListener;
import software.amazon.awssdk.utils.Logger;

/**
* An implementation of {@link ProgressListener} that logs a progress bar at the {@code INFO} level for upload operations. This
* implementation effectively limits the frequency of updates by limiting logging to events of progress advancement. By default,
* the progress bar has {@value #DEFAULT_MAX_TICKS} ticks, meaning an update is logged for every 5% progression, at most.
*/
@SdkPublicApi
public final class LoggingProgressListener implements ProgressListener {
private static final Logger log = Logger.loggerFor(LoggingProgressListener.class);
private static final int DEFAULT_MAX_TICKS = 20;
private final ProgressBar progressBar;

private LoggingProgressListener(int maxTicks) {
progressBar = new ProgressBar(maxTicks);
}

/**
* Create an instance of {@link LoggingProgressListener} with a custom {@code maxTicks} value.
*
* @param maxTicks the number of ticks in the logged progress bar
*/
public static LoggingProgressListener create(int maxTicks) {
return new LoggingProgressListener(maxTicks);
}

/**
* Create an instance of {@link LoggingProgressListener} with the default configuration.
*/
public static LoggingProgressListener create() {
return new LoggingProgressListener(DEFAULT_MAX_TICKS);
}


@Override
public void requestPrepared(Context.RequestPrepared context) {
log.info(() -> "Request Prepared...");
context.uploadProgressSnapshot().ratioTransferred().ifPresent(progressBar::update);
}

@Override
public void requestHeaderSent(Context.RequestHeaderSent context) {
context.uploadProgressSnapshot().ratioTransferred().ifPresent(progressBar::update);
}

@Override
public void requestBytesSent(Context.RequestBytesSent context) {
context.uploadProgressSnapshot().ratioTransferred().ifPresent(progressBar::update);
}

@Override
public void responseHeaderReceived(Context.ResponseHeaderReceived context) {
log.info(() -> "Upload Successful! Starting Download...");
context.downloadProgressSnapshot().ratioTransferred().ifPresent(progressBar::update);
}

@Override
public void responseBytesReceived(Context.ResponseBytesReceived context) {
context.downloadProgressSnapshot().ratioTransferred().ifPresent(progressBar::update);
}

@Override
public void executionSuccess(Context.ExecutionSuccess context) {
log.info(() -> "Execution Successful!");
context.downloadProgressSnapshot().ratioTransferred().ifPresent(progressBar::update);
}

@Override
public void executionFailure(Context.ExecutionFailure context) {
log.warn(() -> "Execution Failed!", context.exception());
}

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

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

void update(double ratio) {
int ticks = (int) Math.floor(ratio * maxTicks);
if (prevTicks.getAndSet(ticks) != ticks) {
log.info(() -> 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();
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,12 @@ public void responseBytesReceived(Context.ResponseBytesReceived context) {
}

@Override
public void attemptFailure(Context.AttemptFailure context) {
public void attemptFailure(Context.ExecutionFailure context) {
forEach(listener -> listener.attemptFailure(context));
}

@Override
public void attemptFailureResponseBytesReceived(Context.AttemptFailureResponseBytesReceived context) {
public void attemptFailureResponseBytesReceived(Context.ExecutionFailure context) {
forEach(listener -> listener.attemptFailureResponseBytesReceived(context));
}

Expand Down
Loading
Loading