Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces global timeout handling for resumable uploads in ResumableUploadChunkCoordinator using a scheduled executor to trigger a DeadlineExceededException if the upload exceeds the specified duration. It also includes comprehensive unit tests to verify timeout behavior, clean cancellations, and payload stream closure. The review feedback highlights two key improvements: ensuring thread safety by reading uploadSessionUrl within a synchronized block in onTimeout(), and preventing potential test hangs by specifying timeouts on future.get() calls in the newly added unit tests.
| private void onTimeout() { | ||
| synchronized (lock) { | ||
| if (done) { | ||
| return; | ||
| } | ||
| } | ||
| String message = | ||
| uploadSessionUrl != null | ||
| ? "Resumable upload timed out for session: " + uploadSessionUrl | ||
| : "Resumable upload timed out before session initiation completed"; | ||
| finish(null, new DeadlineExceededException(message, null, TIMEOUT_STATUS_CODE, false)); | ||
| } |
There was a problem hiding this comment.
The field uploadSessionUrl is read outside of the synchronized (lock) block. If uploadSessionUrl is not declared volatile or is guarded by lock, this can lead to a data race and memory visibility issues across threads (e.g., the timeout thread might see a stale null value even after the session URL has been initialized). To ensure thread safety and consistent visibility, read uploadSessionUrl inside the synchronized (lock) block.
private void onTimeout() {
String sessionUrl;
synchronized (lock) {
if (done) {
return;
}
sessionUrl = uploadSessionUrl;
}
String message =
sessionUrl != null
? "Resumable upload timed out for session: " + sessionUrl
: "Resumable upload timed out before session initiation completed";
finish(null, new DeadlineExceededException(message, null, TIMEOUT_STATUS_CODE, false));
}| ResumableUploadFuture<String> future = | ||
| callable.futureCall("resource-path", streamOf("hello"), timeoutSettings); | ||
|
|
||
| ExecutionException exception = assertThrows(ExecutionException.class, future::get); |
There was a problem hiding this comment.
Calling future.get() without a timeout in a timeout-related unit test can cause the test suite to hang indefinitely if the timeout mechanism fails to fire. It is a best practice to always specify a timeout (e.g., 5 seconds) when waiting on futures in tests to prevent blocking the CI/CD pipeline.
| ExecutionException exception = assertThrows(ExecutionException.class, future::get); | |
| ExecutionException exception = assertThrows(ExecutionException.class, () -> future.get(5, TimeUnit.SECONDS)); |
f7dacda to
ea2e309
Compare
3011b46 to
3e2fdd4
Compare
ea2e309 to
e197ee8
Compare
3e2fdd4 to
4dfdd22
Compare
e197ee8 to
12cd1cb
Compare
4dfdd22 to
3794533
Compare
12cd1cb to
dd1aaac
Compare
497d777 to
a5ffaf3
Compare
7fb2335 to
4795631
Compare
a5ffaf3 to
fc40846
Compare
4795631 to
1fe75dc
Compare
fc40846 to
6960f29
Compare
1fe75dc to
8456db3
Compare
6960f29 to
7d98c7b
Compare
8456db3 to
04da457
Compare
7d98c7b to
a355e4a
Compare
04da457 to
f60b76a
Compare
a355e4a to
c59321f
Compare
f60b76a to
d5c48d6
Compare
c59321f to
bf605a2
Compare
d5c48d6 to
599ab38
Compare
bf605a2 to
aacf3b6
Compare
599ab38 to
292921f
Compare
aacf3b6 to
c36f0cd
Compare
292921f to
85c6f69
Compare
c36f0cd to
17e0368
Compare
85c6f69 to
467ec8c
Compare
17e0368 to
9f3a73f
Compare
59ea76b to
0d9aef5
Compare
9f3a73f to
efea040
Compare
0d9aef5 to
cf10342
Compare
efea040 to
0e50e79
Compare
cf10342 to
26d12d4
Compare
0e50e79 to
2eb5a87
Compare
063af1d to
1e2e399
Compare
2eb5a87 to
c012f3f
Compare
1e2e399 to
7c2f8ff
Compare
c012f3f to
de73081
Compare
7c2f8ff to
56bfa8e
Compare
de73081 to
f128749
Compare
Enforces ResumableUploadCallSettings.getGlobalTimeout() in ResumableUploadChunkCoordinator across the upload lifecycle. Cancels in-flight RPCs and completes the future with DeadlineExceededException when the deadline is exceeded.
56bfa8e to
566ca01
Compare
f128749 to
439bda6
Compare
|
|





Enforces
ResumableUploadCallSettings.getGlobalTimeout()inResumableUploadChunkCoordinatoracross the upload lifecycle. Cancels in-flight RPCs and completes the future withDeadlineExceededExceptionwhen the deadline is exceeded.