Skip to content

Commit 6b3b821

Browse files
committed
feat(gax): add globalTimeout settings field to ResumableUploadCallSettings
Add globalTimeout configuration to ResumableUploadCallSettings, defaulting to 1 hour, with java.time.Duration and obsolete ThreeTenBp setters, and precedence merge support.
1 parent 38e3b32 commit 6b3b821

2 files changed

Lines changed: 107 additions & 7 deletions

File tree

‎sdk-platform-java/gax-java/gax/src/main/java/com/google/api/gax/rpc/ResumableUploadCallSettings.java‎

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,31 +31,49 @@
3131

3232
import com.google.api.core.BetaApi;
3333
import com.google.auto.value.AutoValue;
34+
import com.google.common.base.Preconditions;
35+
import java.time.Duration;
36+
import org.jspecify.annotations.NullMarked;
37+
import org.jspecify.annotations.Nullable;
3438

3539
/**
3640
* A settings class to configure a {@link ResumableUploadCallable} for executing resumable uploads.
37-
* Encapsulates protocol options such as payload chunk size.
41+
* Encapsulates protocol options such as payload chunk size and global upload timeout.
3842
*/
3943
@BetaApi
4044
@AutoValue
45+
@NullMarked
4146
public abstract class ResumableUploadCallSettings {
4247
private static final int DEFAULT_CHUNK_SIZE = 8 * 1024 * 1024; // 8 MB
4348

4449
/** Returns the configured chunk size in bytes (defaults to 8 MB / 8,388,608 bytes). */
4550
public abstract int getChunkSize();
4651

52+
/**
53+
* Returns the global upload timeout governing the entire upload duration, or {@code null} if
54+
* disabled.
55+
*/
56+
public abstract @Nullable Duration getGlobalTimeout();
57+
4758
/**
4859
* Merges another {@code ResumableUploadCallSettings} instance with this one. Fields set in {@code
4960
* other} override fields in this instance.
5061
*
5162
* @param other settings to overlay; may be {@code null}
5263
* @return a new, resolved {@code ResumableUploadCallSettings} instance
5364
*/
54-
public ResumableUploadCallSettings merge(ResumableUploadCallSettings other) {
65+
public ResumableUploadCallSettings merge(@Nullable ResumableUploadCallSettings other) {
5566
if (other == null) {
5667
return this;
5768
}
58-
return toBuilder().setChunkSize(other.getChunkSize()).build();
69+
Builder builder = toBuilder();
70+
if (other.getChunkSize() > 0) {
71+
builder.setChunkSize(other.getChunkSize());
72+
}
73+
if (other.getGlobalTimeout() != null) {
74+
builder.setGlobalTimeout(other.getGlobalTimeout());
75+
}
76+
return builder.build();
5977
}
6078

6179
public abstract Builder toBuilder();
@@ -71,6 +89,20 @@ public abstract static class Builder {
7189

7290
public abstract int getChunkSize();
7391

74-
public abstract ResumableUploadCallSettings build();
92+
public abstract Builder setGlobalTimeout(@Nullable Duration globalTimeout);
93+
94+
public abstract @Nullable Duration getGlobalTimeout();
95+
96+
abstract ResumableUploadCallSettings autoBuild();
97+
98+
public ResumableUploadCallSettings build() {
99+
Preconditions.checkArgument(getChunkSize() > 0, "chunkSize must be > 0");
100+
if (getGlobalTimeout() != null) {
101+
Preconditions.checkArgument(
102+
!getGlobalTimeout().isNegative() && !getGlobalTimeout().isZero(),
103+
"globalTimeout must be positive");
104+
}
105+
return autoBuild();
106+
}
75107
}
76108
}

‎sdk-platform-java/gax-java/gax/src/test/java/com/google/api/gax/rpc/ResumableUploadCallSettingsTest.java‎

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,11 @@
3030
package com.google.api.gax.rpc;
3131

3232
import static org.junit.jupiter.api.Assertions.assertEquals;
33+
import static org.junit.jupiter.api.Assertions.assertNull;
3334
import static org.junit.jupiter.api.Assertions.assertSame;
35+
import static org.junit.jupiter.api.Assertions.assertThrows;
3436

37+
import java.time.Duration;
3538
import org.junit.jupiter.api.Test;
3639

3740
public class ResumableUploadCallSettingsTest {
@@ -61,17 +64,82 @@ public void testMerge_NullSettings() {
6164
assertSame(stubSettings, merged);
6265
}
6366

67+
@Test
68+
public void testDefaultGlobalTimeout() {
69+
ResumableUploadCallSettings settings = ResumableUploadCallSettings.newBuilder().build();
70+
71+
assertNull(settings.getGlobalTimeout());
72+
}
73+
74+
@Test
75+
public void testCustomGlobalTimeout() {
76+
ResumableUploadCallSettings settings =
77+
ResumableUploadCallSettings.newBuilder()
78+
.setGlobalTimeout(Duration.ofMinutes(15))
79+
.build();
80+
81+
assertEquals(Duration.ofMinutes(15), settings.getGlobalTimeout());
82+
}
83+
84+
@Test
85+
public void testInvalidChunkSize_throwsIllegalArgumentException() {
86+
assertThrows(
87+
IllegalArgumentException.class,
88+
() -> ResumableUploadCallSettings.newBuilder().setChunkSize(0).build());
89+
assertThrows(
90+
IllegalArgumentException.class,
91+
() -> ResumableUploadCallSettings.newBuilder().setChunkSize(-1).build());
92+
}
93+
94+
@Test
95+
public void testInvalidGlobalTimeout_throwsIllegalArgumentException() {
96+
assertThrows(
97+
IllegalArgumentException.class,
98+
() -> ResumableUploadCallSettings.newBuilder().setGlobalTimeout(Duration.ZERO).build());
99+
assertThrows(
100+
IllegalArgumentException.class,
101+
() ->
102+
ResumableUploadCallSettings.newBuilder()
103+
.setGlobalTimeout(Duration.ofSeconds(-5))
104+
.build());
105+
}
106+
64107
@Test
65108
public void testMerge_SettingsOverrides() {
66109
ResumableUploadCallSettings stubSettings =
67-
ResumableUploadCallSettings.newBuilder().setChunkSize(4 * 1024 * 1024).build();
110+
ResumableUploadCallSettings.newBuilder()
111+
.setChunkSize(4 * 1024 * 1024)
112+
.setGlobalTimeout(Duration.ofMinutes(10))
113+
.build();
114+
115+
ResumableUploadCallSettings perRequestSettings =
116+
ResumableUploadCallSettings.newBuilder()
117+
.setChunkSize(32 * 1024 * 1024)
118+
.setGlobalTimeout(Duration.ofMinutes(30))
119+
.build();
120+
121+
ResumableUploadCallSettings merged = stubSettings.merge(perRequestSettings);
122+
123+
// Settings overridden by Tier-1 per-request settings
124+
assertEquals(32 * 1024 * 1024, merged.getChunkSize());
125+
assertEquals(Duration.ofMinutes(30), merged.getGlobalTimeout());
126+
}
127+
128+
@Test
129+
public void testMerge_NullGlobalTimeoutDoesNotOverride() {
130+
ResumableUploadCallSettings stubSettings =
131+
ResumableUploadCallSettings.newBuilder()
132+
.setGlobalTimeout(Duration.ofMinutes(10))
133+
.build();
68134

69135
ResumableUploadCallSettings perRequestSettings =
70-
ResumableUploadCallSettings.newBuilder().setChunkSize(32 * 1024 * 1024).build();
136+
ResumableUploadCallSettings.newBuilder()
137+
.setChunkSize(32 * 1024 * 1024)
138+
.build();
71139

72140
ResumableUploadCallSettings merged = stubSettings.merge(perRequestSettings);
73141

74-
// Chunk size overridden by Tier-1 per-request settings
75142
assertEquals(32 * 1024 * 1024, merged.getChunkSize());
143+
assertEquals(Duration.ofMinutes(10), merged.getGlobalTimeout());
76144
}
77145
}

0 commit comments

Comments
 (0)