|
170 | 170 | @SdkPublicApi |
171 | 171 | public final class CloudWatchMetricPublisher implements MetricPublisher { |
172 | 172 | /** |
173 | | - * The maximum queue size for the internal {@link #executor} that is used to aggregate metric data and upload it to |
| 173 | + * The default maximum queue size for the internal {@link #executor} that is used to aggregate metric data and upload it to |
174 | 174 | * CloudWatch. If this value is too high, memory is wasted. If this value is too low, metrics could be dropped. |
175 | | - * |
176 | | - * This value is not currently configurable, because it's unlikely that this is a value that customers should need to modify. |
177 | | - * If customers really need control over this value, we might consider letting them instead configure the |
178 | | - * {@link BlockingQueue} used on the executor. The value here depends on the type of {@code BlockingQueue} in use, and |
179 | | - * we should probably not indirectly couple people to the type of blocking queue we're using. |
180 | 175 | */ |
181 | | - private static final int MAXIMUM_TASK_QUEUE_SIZE = 128; |
| 176 | + private static final int DEFAULT_TASK_QUEUE_SIZE = 128; |
182 | 177 |
|
183 | 178 | private static final String DEFAULT_NAMESPACE = "AwsSdk/JavaSdk2"; |
184 | 179 | private static final int DEFAULT_MAXIMUM_CALLS_PER_UPLOAD = 10; |
@@ -241,7 +236,7 @@ private CloudWatchMetricPublisher(Builder builder) { |
241 | 236 |
|
242 | 237 | // Do not increase above 1 thread: access to MetricCollectionAggregator is not thread safe. |
243 | 238 | this.executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, |
244 | | - new ArrayBlockingQueue<>(MAXIMUM_TASK_QUEUE_SIZE), |
| 239 | + resolveTaskQueue(builder), |
245 | 240 | threadFactory); |
246 | 241 |
|
247 | 242 | long flushFrequencyInMillis = resolveUploadFrequency(builder).toMillis(); |
@@ -285,6 +280,10 @@ private int resolveMaximumCallsPerUpload(Builder builder) { |
285 | 280 | return builder.maximumCallsPerUpload == null ? DEFAULT_MAXIMUM_CALLS_PER_UPLOAD : builder.maximumCallsPerUpload; |
286 | 281 | } |
287 | 282 |
|
| 283 | + private BlockingQueue<Runnable> resolveTaskQueue(Builder builder) { |
| 284 | + return builder.taskQueue == null ? new ArrayBlockingQueue<>(DEFAULT_TASK_QUEUE_SIZE) : builder.taskQueue; |
| 285 | + } |
| 286 | + |
288 | 287 | @Override |
289 | 288 | public void publish(MetricCollection metricCollection) { |
290 | 289 | try { |
@@ -395,6 +394,7 @@ public static final class Builder { |
395 | 394 | private Collection<MetricCategory> metricCategories; |
396 | 395 | private MetricLevel metricLevel; |
397 | 396 | private Collection<SdkMetric<?>> detailedMetrics; |
| 397 | + private BlockingQueue<Runnable> taskQueue; |
398 | 398 |
|
399 | 399 | private Builder() { |
400 | 400 | } |
@@ -467,6 +467,22 @@ public Builder maximumCallsPerUpload(Integer maximumCallsPerUpload) { |
467 | 467 | return this; |
468 | 468 | } |
469 | 469 |
|
| 470 | + /** |
| 471 | + * Configure the {@link BlockingQueue} used by the internal executor for queuing metric aggregation and upload tasks. |
| 472 | + * |
| 473 | + * <p>If this is not specified, a blocking queue with a capacity of 128 is used. |
| 474 | + * |
| 475 | + * <p>High-throughput applications may need a larger queue to prevent dropped metrics. When the queue is full, new |
| 476 | + * metrics are dropped and a warning is logged. |
| 477 | + * |
| 478 | + * @param taskQueue the blocking queue to use for the internal executor |
| 479 | + * @return This object for method chaining. |
| 480 | + */ |
| 481 | + public Builder taskQueue(BlockingQueue<Runnable> taskQueue) { |
| 482 | + this.taskQueue = taskQueue; |
| 483 | + return this; |
| 484 | + } |
| 485 | + |
470 | 486 | /** |
471 | 487 | * Configure the {@link SdkMetric}s that are used to define the {@link Dimension}s metrics are aggregated under. |
472 | 488 | * |
|
0 commit comments