3131
3232import static com .google .common .base .Preconditions .checkNotNull ;
3333
34+ import com .google .api .core .ApiClock ;
3435import com .google .api .core .ApiFuture ;
3536import com .google .api .core .ApiFutureCallback ;
3637import com .google .api .core .ApiFutures ;
38+ import com .google .api .core .NanoClock ;
3739import com .google .api .core .SettableApiFuture ;
3840import com .google .api .gax .resumable .ChunkUploadRequest ;
3941import com .google .api .gax .resumable .ChunkUploadResponse ;
4042import com .google .api .gax .resumable .QueryStatusRequest ;
4143import com .google .api .gax .resumable .QueryStatusResponse ;
44+ import com .google .api .gax .retrying .RetrySettings ;
4245import com .google .api .gax .retrying .RetryingFuture ;
4346import com .google .common .util .concurrent .MoreExecutors ;
4447import java .time .Duration ;
@@ -68,6 +71,8 @@ class ChunkAttemptCallable<ResponseT> implements Callable<ChunkUploadResponse<Re
6871 private final RewindableStreamBuffer buffer ;
6972 private final String uploadUrl ;
7073 private final ApiCallContext originalCallContext ;
74+ private final long deadlineNanos ;
75+ private final ApiClock clock ;
7176
7277 private volatile ChunkUploadRequest currentRequest ;
7378 private volatile ResumableUploadCommand currentCommand ;
@@ -85,6 +90,28 @@ class ChunkAttemptCallable<ResponseT> implements Callable<ChunkUploadResponse<Re
8590 ChunkUploadRequest request ,
8691 ApiCallContext callContext ,
8792 ResumableUploadCommand command ) {
93+ this (
94+ uploadChunkCallable ,
95+ queryStatusCallable ,
96+ buffer ,
97+ uploadUrl ,
98+ request ,
99+ callContext ,
100+ command ,
101+ Long .MAX_VALUE ,
102+ NanoClock .getDefaultClock ());
103+ }
104+
105+ ChunkAttemptCallable (
106+ UnaryCallable <ChunkUploadRequest , ChunkUploadResponse <ResponseT >> uploadChunkCallable ,
107+ UnaryCallable <QueryStatusRequest , QueryStatusResponse <ResponseT >> queryStatusCallable ,
108+ RewindableStreamBuffer buffer ,
109+ String uploadUrl ,
110+ ChunkUploadRequest request ,
111+ ApiCallContext callContext ,
112+ ResumableUploadCommand command ,
113+ long deadlineNanos ,
114+ ApiClock clock ) {
88115 this .uploadChunkCallable =
89116 checkNotNull (uploadChunkCallable , "uploadChunkCallable must not be null" );
90117 this .queryStatusCallable =
@@ -94,6 +121,8 @@ class ChunkAttemptCallable<ResponseT> implements Callable<ChunkUploadResponse<Re
94121 this .currentRequest = checkNotNull (request , "request must not be null" );
95122 this .originalCallContext = checkNotNull (callContext , "callContext must not be null" );
96123 this .currentCommand = checkNotNull (command , "command must not be null" );
124+ this .deadlineNanos = deadlineNanos ;
125+ this .clock = checkNotNull (clock , "clock must not be null" );
97126 }
98127
99128 void setRetryingFuture (RetryingFuture <ChunkUploadResponse <ResponseT >> retryingFuture ) {
@@ -129,9 +158,36 @@ private void prepareAttempt(
129158 SettableApiFuture <ChunkUploadResponse <ResponseT >> attemptFuture ,
130159 ApiCallContext attemptContext ,
131160 RetryingFuture <ChunkUploadResponse <ResponseT >> currentRetryingFuture ) {
161+ // Per GAX-R7: query uses sensible unary defaults trimmed to the remaining global deadline.
162+ long remainingNanos =
163+ deadlineNanos == Long .MAX_VALUE
164+ ? Long .MAX_VALUE
165+ : Math .max (1L , deadlineNanos - clock .nanoTime ());
166+ Duration queryTotal =
167+ Duration .ofNanos (
168+ Math .min (
169+ ResumableUploadCallableImpl .DEFAULT_QUERY_RETRY_SETTINGS
170+ .getTotalTimeoutDuration ()
171+ .toNanos (),
172+ remainingNanos ));
173+ Duration queryRpc =
174+ Duration .ofNanos (
175+ Math .min (
176+ ResumableUploadCallableImpl .DEFAULT_QUERY_RETRY_SETTINGS
177+ .getInitialRpcTimeoutDuration ()
178+ .toNanos (),
179+ queryTotal .toNanos ()));
180+ RetrySettings trimmedQuerySettings =
181+ ResumableUploadCallableImpl .DEFAULT_QUERY_RETRY_SETTINGS .toBuilder ()
182+ .setTotalTimeoutDuration (queryTotal )
183+ .setInitialRpcTimeoutDuration (queryRpc )
184+ .setMaxRpcTimeoutDuration (queryRpc )
185+ .build ();
186+ ApiCallContext queryContext = originalCallContext .withRetrySettings (trimmedQuerySettings );
187+
132188 QueryStatusRequest queryRequest = QueryStatusRequest .create (uploadUrl );
133189 ApiFuture <QueryStatusResponse <ResponseT >> queryFuture =
134- queryStatusCallable .futureCall (queryRequest , attemptContext );
190+ queryStatusCallable .futureCall (queryRequest , queryContext );
135191 if (queryFuture == null ) {
136192 failAttempt (
137193 attemptFuture , new IllegalStateException ("queryStatusCallable returned a null future" ));
0 commit comments