5151 * session. Used with {@link com.google.api.gax.retrying.ScheduledRetryingExecutor}.
5252 *
5353 * <p>Execution follows the standard attempt template with pre-attempt recovery handling. When the
54- * previous attempt failed with a Category 2 ( recoverable) error or missing status header, {@code
54+ * previous attempt failed with a recoverable error or missing status header, {@code
5555 * prepareAttempt} queries session status, realigns the buffer window, tops up from the stream, and
5656 * dispatches the chunk upload request. The callable never blocks on {@code .get()}; results and
5757 * cancellations propagate asynchronously.
@@ -68,6 +68,7 @@ class ChunkAttemptCallable<ResponseT> implements Callable<ChunkUploadResponse<Re
6868 private final RewindableStreamBuffer buffer ;
6969 private final String uploadUrl ;
7070 private final ApiCallContext originalCallContext ;
71+ private final @ Nullable UploadProgressTracker progressTracker ;
7172
7273 private volatile ChunkUploadRequest currentRequest ;
7374 private volatile UploadCommand currentCommand ;
@@ -84,7 +85,8 @@ class ChunkAttemptCallable<ResponseT> implements Callable<ChunkUploadResponse<Re
8485 String uploadUrl ,
8586 ChunkUploadRequest request ,
8687 ApiCallContext callContext ,
87- UploadCommand command ) {
88+ UploadCommand command ,
89+ @ Nullable UploadProgressTracker progressTracker ) {
8890 this .uploadChunkCallable =
8991 checkNotNull (uploadChunkCallable , "uploadChunkCallable must not be null" );
9092 this .queryStatusCallable =
@@ -94,6 +96,7 @@ class ChunkAttemptCallable<ResponseT> implements Callable<ChunkUploadResponse<Re
9496 this .currentRequest = checkNotNull (request , "request must not be null" );
9597 this .originalCallContext = checkNotNull (callContext , "callContext must not be null" );
9698 this .currentCommand = checkNotNull (command , "command must not be null" );
99+ this .progressTracker = progressTracker ;
97100 }
98101
99102 void setRetryingFuture (RetryingFuture <ChunkUploadResponse <ResponseT >> retryingFuture ) {
@@ -128,6 +131,9 @@ private void prepareAttempt(
128131 SettableApiFuture <ChunkUploadResponse <ResponseT >> attemptFuture ,
129132 ApiCallContext attemptContext ,
130133 RetryingFuture <ChunkUploadResponse <ResponseT >> currentRetryingFuture ) {
134+ if (progressTracker != null ) {
135+ progressTracker .onRecovering (lastFailure );
136+ }
131137 QueryStatusRequest queryRequest = QueryStatusRequest .create (uploadUrl );
132138 ApiFuture <QueryStatusResponse <ResponseT >> queryFuture =
133139 queryStatusCallable .futureCall (queryRequest , attemptContext );
@@ -190,14 +196,18 @@ private void handleQuerySuccess(
190196 failAttempt (
191197 attemptFuture ,
192198 RewindableStreamBuffer .protocolViolation (
193- "Incomplete query status response did not include a committed offset for upload URL: "
199+ "Incomplete query status response did not include a committed offset for upload"
200+ + " URL: "
194201 + uploadUrl ));
195202 return ;
196203 }
197204
198205 // Normal path: realign buffer to committedOffset, compact and top up.
199206 try {
200207 buffer .realignTo (committedOffset );
208+ if (progressTracker != null ) {
209+ progressTracker .onOffsetReceived (committedOffset );
210+ }
201211 } catch (Throwable e ) {
202212 failAttempt (attemptFuture , e );
203213 return ;
@@ -207,7 +217,8 @@ private void handleQuerySuccess(
207217 // Preserve upload,finalize for a trailing partial after realignment.
208218 UploadCommand realignedCommand ;
209219 if (buffer .isFinal ()) {
210- realignedCommand = buffer .isEmpty () ? UploadCommand .FINALIZE : UploadCommand .UPLOAD_FINALIZE ;
220+ realignedCommand =
221+ buffer .isEmpty () ? UploadCommand .FINALIZE : UploadCommand .UPLOAD_FINALIZE ;
211222 } else {
212223 realignedCommand = UploadCommand .UPLOAD ;
213224 }
0 commit comments