|
20 | 20 | import com.google.api.gax.grpc.BundlingSettings; |
21 | 21 | import com.google.auth.Credentials; |
22 | 22 | import com.google.auth.oauth2.GoogleCredentials; |
| 23 | +import com.google.auto.value.AutoValue; |
23 | 24 | import com.google.common.base.Optional; |
24 | 25 | import com.google.common.base.Preconditions; |
25 | 26 | import com.google.common.util.concurrent.ListenableFuture; |
26 | 27 | import com.google.pubsub.v1.PubsubMessage; |
27 | 28 | import io.grpc.ManagedChannelBuilder; |
28 | | -import java.io.IOException; |
29 | 29 | import java.util.concurrent.ScheduledExecutorService; |
30 | 30 | import org.joda.time.Duration; |
31 | 31 |
|
|
79 | 79 | * </pre> |
80 | 80 | */ |
81 | 81 | public interface Publisher { |
82 | | - String PUBSUB_API_ADDRESS = "pubsub.googleapis.com"; |
83 | | - String PUBSUB_API_SCOPE = "https://www.googleapis.com/auth/pubsub"; |
84 | | - |
85 | | - // API limits. |
86 | | - int MAX_BUNDLE_MESSAGES = 1000; |
87 | | - int MAX_BUNDLE_BYTES = 10 * 1000 * 1000; // 10 megabytes (https://en.wikipedia.org/wiki/Megabyte) |
88 | | - |
89 | | - // Meaningful defaults. |
90 | | - long DEFAULT_MAX_BUNDLE_MESSAGES = 100L; |
91 | | - long DEFAULT_MAX_BUNDLE_BYTES = 1000L; // 1 kB |
92 | | - Duration DEFAULT_MAX_BUNDLE_DURATION = new Duration(1); // 1ms |
93 | | - Duration DEFAULT_REQUEST_TIMEOUT = new Duration(10 * 1000); // 10 seconds |
94 | | - Duration MIN_SEND_BUNDLE_DURATION = new Duration(10 * 1000); // 10 seconds |
95 | | - Duration MIN_REQUEST_TIMEOUT = new Duration(10); // 10 milliseconds |
96 | | - |
97 | | - BundlingSettings DEFAULT_BUNDLING_SETTINGS = |
98 | | - BundlingSettings.newBuilder() |
99 | | - .setDelayThreshold(DEFAULT_MAX_BUNDLE_DURATION) |
100 | | - .setRequestByteThreshold(DEFAULT_MAX_BUNDLE_BYTES) |
101 | | - .setElementCountThreshold(DEFAULT_MAX_BUNDLE_MESSAGES) |
102 | | - .build(); |
103 | | - |
104 | 82 | /** Topic to which the publisher publishes to. */ |
105 | 83 | String getTopic(); |
106 | 84 |
|
@@ -161,130 +139,115 @@ public interface Publisher { |
161 | 139 | */ |
162 | 140 | void shutdown(); |
163 | 141 |
|
164 | | - /** A builder of {@link Publisher}s. */ |
165 | | - final class Builder { |
166 | | - String topic; |
| 142 | + @AutoValue |
| 143 | + public abstract class Settings { |
| 144 | + static final String PUBSUB_API_ADDRESS = "pubsub.googleapis.com"; |
| 145 | + static final String PUBSUB_API_SCOPE = "https://www.googleapis.com/auth/pubsub"; |
167 | 146 |
|
168 | | - // Bundling options |
169 | | - BundlingSettings bundlingSettings = DEFAULT_BUNDLING_SETTINGS; |
| 147 | + // API limits. |
| 148 | + static final int MAX_BUNDLE_MESSAGES = 1000; |
| 149 | + static final int MAX_BUNDLE_BYTES = |
| 150 | + 10 * 1000 * 1000; // 10 megabytes (https://en.wikipedia.org/wiki/Megabyte) |
170 | 151 |
|
171 | | - // Client-side flow control options |
172 | | - FlowController.Settings flowControlSettings = FlowController.Settings.DEFAULT; |
173 | | - boolean failOnFlowControlLimits = false; |
| 152 | + // Meaningful defaults. |
| 153 | + static final long DEFAULT_MAX_BUNDLE_MESSAGES = 100L; |
| 154 | + static final long DEFAULT_MAX_BUNDLE_BYTES = 1000L; // 1 kB |
| 155 | + static final Duration DEFAULT_MAX_BUNDLE_DURATION = new Duration(1); // 1ms |
| 156 | + static final Duration DEFAULT_REQUEST_TIMEOUT = new Duration(10 * 1000); // 10 seconds |
| 157 | + static final Duration MIN_SEND_BUNDLE_DURATION = new Duration(10 * 1000); // 10 seconds |
| 158 | + static final Duration MIN_REQUEST_TIMEOUT = new Duration(10); // 10 milliseconds |
174 | 159 |
|
175 | | - // Send bundle deadline |
176 | | - Duration sendBundleDeadline = MIN_SEND_BUNDLE_DURATION; |
| 160 | + static final BundlingSettings DEFAULT_BUNDLING_SETTINGS = |
| 161 | + BundlingSettings.newBuilder() |
| 162 | + .setDelayThreshold(DEFAULT_MAX_BUNDLE_DURATION) |
| 163 | + .setRequestByteThreshold(DEFAULT_MAX_BUNDLE_BYTES) |
| 164 | + .setElementCountThreshold(DEFAULT_MAX_BUNDLE_MESSAGES) |
| 165 | + .build(); |
177 | 166 |
|
178 | | - // RPC options |
179 | | - Duration requestTimeout = DEFAULT_REQUEST_TIMEOUT; |
| 167 | + public static Settings DEFAULT = newBuilder().build(); |
180 | 168 |
|
181 | | - // Channels and credentials |
182 | | - Optional<Credentials> userCredentials = Optional.absent(); |
183 | | - Optional<ManagedChannelBuilder<? extends ManagedChannelBuilder<?>>> channelBuilder = |
184 | | - Optional.absent(); |
| 169 | + public abstract BundlingSettings getBundlingSettings(); |
185 | 170 |
|
186 | | - Optional<ScheduledExecutorService> executor = Optional.absent(); |
| 171 | + public abstract FlowController.Settings getFlowControlSettings(); |
187 | 172 |
|
188 | | - /** Constructs a new {@link Builder} using the given topic. */ |
189 | | - public static Builder newBuilder(String topic) { |
190 | | - return new Builder(topic); |
191 | | - } |
| 173 | + public abstract boolean getFailOnFlowControlLimits(); |
192 | 174 |
|
193 | | - Builder(String topic) { |
194 | | - this.topic = Preconditions.checkNotNull(topic); |
195 | | - } |
| 175 | + abstract Duration getSendBundleDeadline(); |
196 | 176 |
|
197 | | - /** |
198 | | - * Credentials to authenticate with. |
199 | | - * |
200 | | - * <p>Must be properly scoped for accessing Cloud Pub/Sub APIs. |
201 | | - */ |
202 | | - public Builder setCredentials(Credentials userCredentials) { |
203 | | - this.userCredentials = Optional.of(Preconditions.checkNotNull(userCredentials)); |
204 | | - return this; |
205 | | - } |
| 177 | + abstract Duration getRequestTimeout(); |
206 | 178 |
|
207 | | - /** |
208 | | - * ManagedChannelBuilder to use to create Channels. |
209 | | - * |
210 | | - * <p>Must point at Cloud Pub/Sub endpoint. |
211 | | - */ |
212 | | - public Builder setChannelBuilder( |
213 | | - ManagedChannelBuilder<? extends ManagedChannelBuilder<?>> channelBuilder) { |
214 | | - this.channelBuilder = |
215 | | - Optional.<ManagedChannelBuilder<? extends ManagedChannelBuilder<?>>>of( |
216 | | - Preconditions.checkNotNull(channelBuilder)); |
217 | | - return this; |
218 | | - } |
| 179 | + abstract Optional<Credentials> getUserCredentials(); |
219 | 180 |
|
220 | | - // Bundling options |
221 | | - public Builder setBundlingSettings(BundlingSettings bundlingSettings) { |
222 | | - Preconditions.checkNotNull(bundlingSettings); |
223 | | - Preconditions.checkNotNull(bundlingSettings.getElementCountThreshold()); |
224 | | - Preconditions.checkArgument(bundlingSettings.getElementCountThreshold() > 0); |
225 | | - Preconditions.checkNotNull(bundlingSettings.getRequestByteThreshold()); |
226 | | - Preconditions.checkArgument(bundlingSettings.getRequestByteThreshold() > 0); |
227 | | - Preconditions.checkNotNull(bundlingSettings.getDelayThreshold()); |
228 | | - Preconditions.checkArgument(bundlingSettings.getDelayThreshold().getMillis() > 0); |
229 | | - |
230 | | - Preconditions.checkArgument( |
231 | | - bundlingSettings.getElementCountLimit() == null, |
232 | | - "elementCountLimit option not honored by current implementation"); |
233 | | - Preconditions.checkArgument( |
234 | | - bundlingSettings.getRequestByteLimit() == null, |
235 | | - "requestByteLimit option not honored by current implementation"); |
236 | | - Preconditions.checkArgument( |
237 | | - bundlingSettings.getBlockingCallCountThreshold() == null, |
238 | | - "blockingCallCountThreshold option not honored by current implementation"); |
239 | | - |
240 | | - this.bundlingSettings = bundlingSettings; |
241 | | - return this; |
242 | | - } |
| 181 | + abstract Optional<ManagedChannelBuilder<? extends ManagedChannelBuilder<?>>> |
| 182 | + getChannelBuilder(); |
243 | 183 |
|
244 | | - // Flow control options |
| 184 | + abstract Optional<ScheduledExecutorService> getExecutor(); |
245 | 185 |
|
246 | | - /** Sets the flow control settings. */ |
247 | | - public Builder setFlowControlSettings(FlowController.Settings flowControlSettings) { |
248 | | - this.flowControlSettings = Preconditions.checkNotNull(flowControlSettings); |
249 | | - return this; |
| 186 | + public static Builder newBuilder() { |
| 187 | + return new AutoValue_Publisher_Settings.Builder() |
| 188 | + .setFlowControlSettings(FlowController.Settings.DEFAULT) |
| 189 | + .setFailOnFlowControlLimits(false) |
| 190 | + .setSendBundleDeadline(MIN_SEND_BUNDLE_DURATION) |
| 191 | + .setRequestTimeout(DEFAULT_REQUEST_TIMEOUT) |
| 192 | + .setUserCredentials(Optional.<Credentials>absent()) |
| 193 | + .setChannelBuilder( |
| 194 | + Optional.<ManagedChannelBuilder<? extends ManagedChannelBuilder<?>>>absent()) |
| 195 | + .setExecutor(Optional.<ScheduledExecutorService>absent()) |
| 196 | + .setBundlingSettings(DEFAULT_BUNDLING_SETTINGS); |
250 | 197 | } |
251 | 198 |
|
252 | | - /** |
253 | | - * Whether to fail publish when reaching any of the flow control limits, with either a {@link |
254 | | - * RequestByteMaxOutstandingReachedException} or {@link |
255 | | - * ElementCountMaxOutstandingReachedException} as appropriate. |
256 | | - * |
257 | | - * <p>If set to false, then publish operations will block the current thread until the |
258 | | - * outstanding requests go under the limits. |
259 | | - */ |
260 | | - public Builder setFailOnFlowControlLimits(boolean fail) { |
261 | | - failOnFlowControlLimits = fail; |
262 | | - return this; |
263 | | - } |
| 199 | + @AutoValue.Builder |
| 200 | + abstract static class Builder { |
| 201 | + public abstract Builder setBundlingSettings(BundlingSettings value); |
264 | 202 |
|
265 | | - /** Maximum time to attempt sending (and retrying) a bundle of messages before giving up. */ |
266 | | - public Builder setSendBundleDeadline(Duration deadline) { |
267 | | - Preconditions.checkArgument(deadline.compareTo(MIN_SEND_BUNDLE_DURATION) >= 0); |
268 | | - sendBundleDeadline = deadline; |
269 | | - return this; |
270 | | - } |
| 203 | + public abstract Builder setFlowControlSettings(FlowController.Settings value); |
271 | 204 |
|
272 | | - // Runtime options |
273 | | - /** Time to wait for a publish call to return from the server. */ |
274 | | - public Builder setRequestTimeout(Duration timeout) { |
275 | | - Preconditions.checkArgument(timeout.compareTo(MIN_REQUEST_TIMEOUT) >= 0); |
276 | | - requestTimeout = timeout; |
277 | | - return this; |
278 | | - } |
| 205 | + public abstract Builder setFailOnFlowControlLimits(boolean value); |
279 | 206 |
|
280 | | - /** Gives the ability to set a custom executor to be used by the library. */ |
281 | | - public Builder setExecutor(ScheduledExecutorService executor) { |
282 | | - this.executor = Optional.of(Preconditions.checkNotNull(executor)); |
283 | | - return this; |
284 | | - } |
| 207 | + abstract Builder setSendBundleDeadline(Duration value); |
| 208 | + |
| 209 | + abstract Builder setRequestTimeout(Duration value); |
| 210 | + |
| 211 | + abstract Builder setUserCredentials(Optional<Credentials> value); |
| 212 | + |
| 213 | + Builder setUserCredentials(Credentials value) { |
| 214 | + return setUserCredentials(Optional.of(value)); |
| 215 | + } |
| 216 | + |
| 217 | + abstract Builder setChannelBuilder( |
| 218 | + Optional<ManagedChannelBuilder<? extends ManagedChannelBuilder<?>>> value); |
| 219 | + |
| 220 | + Builder setChannelBuilder(ManagedChannelBuilder<? extends ManagedChannelBuilder<?>> value) { |
| 221 | + return setChannelBuilder( |
| 222 | + Optional.<ManagedChannelBuilder<? extends ManagedChannelBuilder<?>>>of(value)); |
| 223 | + } |
| 224 | + |
| 225 | + abstract Builder setExecutor(Optional<ScheduledExecutorService> value); |
| 226 | + |
| 227 | + Builder setExecutor(ScheduledExecutorService value) { |
| 228 | + return setExecutor(Optional.of(value)); |
| 229 | + } |
| 230 | + |
| 231 | + abstract Settings autoBuild(); |
| 232 | + |
| 233 | + public Settings build() { |
| 234 | + Settings settings = autoBuild(); |
| 235 | + Preconditions.checkArgument( |
| 236 | + settings.getBundlingSettings().getElementCountLimit() == null, |
| 237 | + "elementCountLimit option not honored by current implementation"); |
| 238 | + Preconditions.checkArgument( |
| 239 | + settings.getBundlingSettings().getRequestByteLimit() == null, |
| 240 | + "requestByteLimit option not honored by current implementation"); |
| 241 | + Preconditions.checkArgument( |
| 242 | + settings.getBundlingSettings().getBlockingCallCountThreshold() == null, |
| 243 | + "blockingCallCountThreshold option not honored by current implementation"); |
285 | 244 |
|
286 | | - public Publisher build() throws IOException { |
287 | | - return new PublisherImpl(this); |
| 245 | + Preconditions.checkArgument( |
| 246 | + settings.getRequestTimeout().compareTo(MIN_REQUEST_TIMEOUT) >= 0); |
| 247 | + Preconditions.checkArgument( |
| 248 | + settings.getSendBundleDeadline().compareTo(MIN_SEND_BUNDLE_DURATION) >= 0); |
| 249 | + return settings; |
| 250 | + } |
288 | 251 | } |
289 | 252 | } |
290 | 253 | } |
0 commit comments