Repository navigation
Expand file tree
/
Copy pathRequestOptions.java
More file actions
142 lines (117 loc) · 4.68 KB
/
Copy pathRequestOptions.java
File metadata and controls
142 lines (117 loc) · 4.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package dev.getchat.sdk;
import java.time.Duration;
import java.util.Objects;
import org.jspecify.annotations.Nullable;
/**
* Request-reliability settings. Set instance-wide on {@link GetChatClient}, and
* overridable per call via {@link RequestControl}.
*
* <p>Bounds are validated on construction so a typo fails fast rather than
* quietly hammering the backend. Durations must be non-negative;
* {@link Duration#ZERO} is the documented way to disable the per-attempt
* timeout (and to skip the backoff wait).
*/
public final class RequestOptions {
/** Per-attempt timeout, stored as milliseconds; 0 disables it. */
private final long timeout;
/** Retry attempts after the first failure; 0 disables retrying. */
private final int retries;
/** Base backoff delay in milliseconds (exponential with jitter). */
private final long retryDelay;
public static final long DEFAULT_TIMEOUT_MS = 30_000L;
public static final int DEFAULT_RETRIES = 2;
public static final long DEFAULT_RETRY_DELAY_MS = 200L;
/** Same cap as the node SDK, so a {@code retries: 10000} typo is rejected. */
public static final int MAX_RETRIES = 10;
private RequestOptions(long timeout, int retries, long retryDelay) {
this.timeout = validateNonNegative(timeout, "timeout");
this.retryDelay = validateNonNegative(retryDelay, "retryDelay");
if (retries < 0 || retries > MAX_RETRIES) {
throw new GetChatException("retries must be between 0 and " + MAX_RETRIES + ", got " + retries);
}
this.retries = retries;
}
private static long validateNonNegative(long value, String name) {
if (value < 0) {
throw new GetChatException(name + " must be >= 0, got " + value);
}
return value;
}
public static RequestOptions defaults() {
return builder().build();
}
public static Builder builder() {
return new Builder();
}
/** Per-attempt timeout; {@link Duration#ZERO} means no per-attempt deadline. */
public Duration timeout() {
return Duration.ofMillis(timeout);
}
public int retries() {
return retries;
}
/** Base backoff delay (exponential with jitter); {@link Duration#ZERO} skips the wait. */
public Duration retryDelay() {
return Duration.ofMillis(retryDelay);
}
/**
* Base backoff delay in milliseconds, for the internal retry machinery which
* works in millis. Package-private: the public surface speaks {@link Duration}.
*/
long retryDelayMillis() {
return retryDelay;
}
/** Equal to another {@code RequestOptions} with the same timeout, retries and delay. */
@Override
public boolean equals(@Nullable Object o) {
return this == o
|| (o instanceof RequestOptions other
&& timeout == other.timeout
&& retries == other.retries
&& retryDelay == other.retryDelay);
}
@Override
public int hashCode() {
return Objects.hash(timeout, retries, retryDelay);
}
@Override
public String toString() {
return "RequestOptions{timeout=" + timeout + ", retries=" + retries + ", retryDelay=" + retryDelay + "}";
}
/** Builder for {@link RequestOptions}. */
public static final class Builder {
private long timeout = DEFAULT_TIMEOUT_MS;
private int retries = DEFAULT_RETRIES;
private long retryDelay = DEFAULT_RETRY_DELAY_MS;
private Builder() {}
/**
* Per-attempt timeout. {@link Duration#ZERO} disables the deadline.
*
* @throws NullPointerException if {@code timeout} is null — it is a
* required, non-null setting (this package is {@code @NullMarked})
*/
public Builder timeout(Duration timeout) {
this.timeout =
Objects.requireNonNull(timeout, "timeout is required").toMillis();
return this;
}
public Builder retries(int retries) {
this.retries = retries;
return this;
}
/**
* Base backoff delay. {@link Duration#ZERO} skips the wait between retries.
*
* @throws NullPointerException if {@code retryDelay} is null — it is a
* required, non-null setting (this package is {@code @NullMarked})
*/
public Builder retryDelay(Duration retryDelay) {
this.retryDelay =
Objects.requireNonNull(retryDelay, "retryDelay is required").toMillis();
return this;
}
public RequestOptions build() {
return new RequestOptions(timeout, retries, retryDelay);
}
}
}