0
# Endpoint Discovery & Dynamic Endpoints
1
2
AWS services may support endpoint discovery to optimize connectivity and performance. The AWS Java SDK Core provides endpoint discovery capabilities that automatically discover and cache service endpoints, especially useful for services with dynamic or regionalized endpoints.
3
4
## Core Endpoint Discovery Interfaces
5
6
### Endpoint Discovery Provider
7
8
```java { .api }
9
// Core endpoint discovery provider interface
10
interface EndpointDiscoveryProvider {
11
boolean isEndpointDiscoveryEnabled();
12
void refresh();
13
}
14
15
// Base endpoint discovery provider
16
abstract class BaseEndpointDiscoveryProvider implements EndpointDiscoveryProvider {
17
public abstract boolean isEndpointDiscoveryEnabled();
18
public void refresh() {
19
// Default refresh implementation
20
}
21
}
22
```
23
24
### Endpoint Discovery Provider Chain
25
26
```java { .api }
27
// Chain of endpoint discovery providers
28
class EndpointDiscoveryProviderChain extends BaseEndpointDiscoveryProvider {
29
public EndpointDiscoveryProviderChain(EndpointDiscoveryProvider... providers);
30
public EndpointDiscoveryProviderChain(List<EndpointDiscoveryProvider> providers);
31
32
public boolean isEndpointDiscoveryEnabled();
33
public void refresh();
34
35
// Get the current provider in the chain that provided the result
36
public EndpointDiscoveryProvider getLastUsedProvider();
37
}
38
39
// Default endpoint discovery provider chain
40
class DefaultEndpointDiscoveryProviderChain extends EndpointDiscoveryProviderChain {
41
public static DefaultEndpointDiscoveryProviderChain getInstance();
42
43
// Uses the following provider chain:
44
// 1. Environment variable provider
45
// 2. System property provider
46
// 3. AWS profile provider
47
// 4. Default disabled provider
48
}
49
```
50
51
## Built-in Endpoint Discovery Providers
52
53
### Environment Variable Provider
54
55
```java { .api }
56
// Endpoint discovery from environment variables
57
class EnvironmentVariableEndpointDiscoveryProvider extends BaseEndpointDiscoveryProvider {
58
public static final String AWS_ENABLE_ENDPOINT_DISCOVERY = "AWS_ENABLE_ENDPOINT_DISCOVERY";
59
60
public EnvironmentVariableEndpointDiscoveryProvider();
61
public boolean isEndpointDiscoveryEnabled();
62
}
63
```
64
65
### System Property Provider
66
67
```java { .api }
68
// Endpoint discovery from system properties
69
class SystemPropertyEndpointDiscoveryProvider extends BaseEndpointDiscoveryProvider {
70
public static final String AWS_ENABLE_ENDPOINT_DISCOVERY = "aws.enableEndpointDiscovery";
71
72
public SystemPropertyEndpointDiscoveryProvider();
73
public boolean isEndpointDiscoveryEnabled();
74
}
75
```
76
77
### AWS Profile Provider
78
79
```java { .api }
80
// Endpoint discovery from AWS profile configuration
81
class AwsProfileEndpointDiscoveryProvider extends BaseEndpointDiscoveryProvider {
82
public AwsProfileEndpointDiscoveryProvider();
83
public AwsProfileEndpointDiscoveryProvider(String profileName);
84
public AwsProfileEndpointDiscoveryProvider(File profileFile);
85
public AwsProfileEndpointDiscoveryProvider(File profileFile, String profileName);
86
87
public boolean isEndpointDiscoveryEnabled();
88
}
89
```
90
91
### Static Provider
92
93
```java { .api }
94
// Static endpoint discovery configuration
95
class StaticEndpointDiscoveryProvider extends BaseEndpointDiscoveryProvider {
96
public StaticEndpointDiscoveryProvider(boolean endpointDiscoveryEnabled);
97
public boolean isEndpointDiscoveryEnabled();
98
}
99
```
100
101
## Endpoint Discovery Configuration
102
103
### Client Builder Integration
104
105
```java
106
import com.amazonaws.endpointdiscovery.DefaultEndpointDiscoveryProviderChain;
107
import com.amazonaws.endpointdiscovery.StaticEndpointDiscoveryProvider;
108
import com.amazonaws.services.timestreamwrite.AmazonTimestreamWrite;
109
import com.amazonaws.services.timestreamwrite.AmazonTimestreamWriteClientBuilder;
110
111
// Enable endpoint discovery using default provider chain
112
AmazonTimestreamWrite client = AmazonTimestreamWriteClientBuilder.standard()
113
.withCredentials(DefaultAWSCredentialsProviderChain.getInstance())
114
.withRegion(Regions.US_EAST_1)
115
.withEndpointDiscoveryEnabled(true)
116
.build();
117
118
// Or use explicit endpoint discovery provider
119
EndpointDiscoveryProvider provider = new StaticEndpointDiscoveryProvider(true);
120
AmazonTimestreamWrite clientWithProvider = AmazonTimestreamWriteClientBuilder.standard()
121
.withCredentials(DefaultAWSCredentialsProviderChain.getInstance())
122
.withRegion(Regions.US_EAST_1)
123
.withEndpointDiscoveryProvider(provider)
124
.build();
125
```
126
127
### Environment Configuration
128
129
```bash
130
# Enable endpoint discovery via environment variable
131
export AWS_ENABLE_ENDPOINT_DISCOVERY=true
132
133
# Or via system property
134
java -Daws.enableEndpointDiscovery=true YourApplication
135
```
136
137
### Profile Configuration
138
139
```ini
140
# In ~/.aws/config or credentials file
141
[profile my-profile]
142
endpoint_discovery_enabled = true
143
region = us-west-2
144
145
[default]
146
endpoint_discovery_enabled = false
147
```
148
149
## Basic Usage Examples
150
151
### Simple Endpoint Discovery Setup
152
153
```java
154
import com.amazonaws.endpointdiscovery.DefaultEndpointDiscoveryProviderChain;
155
import com.amazonaws.services.timestreamwrite.AmazonTimestreamWrite;
156
import com.amazonaws.services.timestreamwrite.AmazonTimestreamWriteClientBuilder;
157
158
public class EndpointDiscoveryExample {
159
160
public static void main(String[] args) {
161
// Create client with endpoint discovery enabled
162
AmazonTimestreamWrite timestreamClient = AmazonTimestreamWriteClientBuilder.standard()
163
.withCredentials(DefaultAWSCredentialsProviderChain.getInstance())
164
.withRegion(Regions.US_EAST_1)
165
.withEndpointDiscoveryEnabled(true)
166
.build();
167
168
try {
169
// Use the client - endpoints will be discovered automatically
170
timestreamClient.listDatabases();
171
172
} finally {
173
// Clean up
174
timestreamClient.shutdown();
175
}
176
}
177
}
178
```
179
180
### Custom Endpoint Discovery Provider
181
182
```java
183
import com.amazonaws.endpointdiscovery.BaseEndpointDiscoveryProvider;
184
185
public class CustomEndpointDiscoveryProvider extends BaseEndpointDiscoveryProvider {
186
private final String configSource;
187
private volatile Boolean endpointDiscoveryEnabled;
188
189
public CustomEndpointDiscoveryProvider(String configSource) {
190
this.configSource = configSource;
191
}
192
193
@Override
194
public boolean isEndpointDiscoveryEnabled() {
195
if (endpointDiscoveryEnabled == null) {
196
// Load configuration from custom source
197
endpointDiscoveryEnabled = loadConfigurationFromSource();
198
}
199
return endpointDiscoveryEnabled;
200
}
201
202
@Override
203
public void refresh() {
204
// Force reload from configuration source
205
endpointDiscoveryEnabled = null;
206
}
207
208
private boolean loadConfigurationFromSource() {
209
// Custom logic to load endpoint discovery configuration
210
// For example, from database, external service, etc.
211
try {
212
// Your custom configuration loading logic here
213
return fetchEndpointDiscoverySettingFromSource(configSource);
214
} catch (Exception e) {
215
// Default to disabled on error
216
return false;
217
}
218
}
219
220
private boolean fetchEndpointDiscoverySettingFromSource(String source) {
221
// Implement your custom configuration fetching logic
222
return true; // Placeholder
223
}
224
}
225
```
226
227
### Provider Chain Configuration
228
229
```java
230
import com.amazonaws.endpointdiscovery.EndpointDiscoveryProviderChain;
231
import com.amazonaws.endpointdiscovery.EnvironmentVariableEndpointDiscoveryProvider;
232
import com.amazonaws.endpointdiscovery.AwsProfileEndpointDiscoveryProvider;
233
import com.amazonaws.endpointdiscovery.StaticEndpointDiscoveryProvider;
234
235
// Create custom provider chain
236
EndpointDiscoveryProvider customChain = new EndpointDiscoveryProviderChain(
237
new EnvironmentVariableEndpointDiscoveryProvider(),
238
new CustomEndpointDiscoveryProvider("my-config-source"),
239
new AwsProfileEndpointDiscoveryProvider(),
240
new StaticEndpointDiscoveryProvider(false) // Default fallback
241
);
242
243
// Use custom chain in client
244
AmazonTimestreamWrite client = AmazonTimestreamWriteClientBuilder.standard()
245
.withCredentials(DefaultAWSCredentialsProviderChain.getInstance())
246
.withRegion(Regions.US_EAST_1)
247
.withEndpointDiscoveryProvider(customChain)
248
.build();
249
```
250
251
## Advanced Endpoint Discovery Patterns
252
253
### Conditional Endpoint Discovery
254
255
```java
256
public class ConditionalEndpointDiscoveryProvider extends BaseEndpointDiscoveryProvider {
257
private final String environment;
258
private final Map<String, Boolean> environmentSettings;
259
260
public ConditionalEndpointDiscoveryProvider(String environment) {
261
this.environment = environment;
262
this.environmentSettings = Map.of(
263
"production", true,
264
"staging", true,
265
"development", false,
266
"test", false
267
);
268
}
269
270
@Override
271
public boolean isEndpointDiscoveryEnabled() {
272
return environmentSettings.getOrDefault(environment, false);
273
}
274
}
275
276
// Usage
277
EndpointDiscoveryProvider conditionalProvider =
278
new ConditionalEndpointDiscoveryProvider(System.getProperty("environment", "development"));
279
```
280
281
### Service-Specific Endpoint Discovery
282
283
```java
284
public class ServiceSpecificEndpointDiscoveryProvider extends BaseEndpointDiscoveryProvider {
285
private final String serviceName;
286
private final Map<String, Boolean> serviceSettings;
287
288
public ServiceSpecificEndpointDiscoveryProvider(String serviceName) {
289
this.serviceName = serviceName;
290
this.serviceSettings = loadServiceSettings();
291
}
292
293
@Override
294
public boolean isEndpointDiscoveryEnabled() {
295
return serviceSettings.getOrDefault(serviceName, false);
296
}
297
298
private Map<String, Boolean> loadServiceSettings() {
299
// Configure endpoint discovery per service
300
return Map.of(
301
"timestream-write", true,
302
"timestream-query", true,
303
"dax", true,
304
"s3", false,
305
"dynamodb", false
306
);
307
}
308
}
309
```
310
311
### Caching Endpoint Discovery Provider
312
313
```java
314
public class CachingEndpointDiscoveryProvider extends BaseEndpointDiscoveryProvider {
315
private final EndpointDiscoveryProvider delegate;
316
private final long cacheTimeoutMs;
317
private volatile Boolean cachedResult;
318
private volatile long lastCacheTime;
319
320
public CachingEndpointDiscoveryProvider(EndpointDiscoveryProvider delegate, long cacheTimeoutMs) {
321
this.delegate = delegate;
322
this.cacheTimeoutMs = cacheTimeoutMs;
323
}
324
325
@Override
326
public boolean isEndpointDiscoveryEnabled() {
327
long currentTime = System.currentTimeMillis();
328
329
if (cachedResult == null || (currentTime - lastCacheTime) > cacheTimeoutMs) {
330
cachedResult = delegate.isEndpointDiscoveryEnabled();
331
lastCacheTime = currentTime;
332
}
333
334
return cachedResult;
335
}
336
337
@Override
338
public void refresh() {
339
cachedResult = null;
340
delegate.refresh();
341
}
342
}
343
```
344
345
## Error Handling and Fallbacks
346
347
### Resilient Endpoint Discovery
348
349
```java
350
public class ResilientEndpointDiscoveryProvider extends BaseEndpointDiscoveryProvider {
351
private final List<EndpointDiscoveryProvider> providers;
352
private final boolean defaultOnError;
353
354
public ResilientEndpointDiscoveryProvider(List<EndpointDiscoveryProvider> providers, boolean defaultOnError) {
355
this.providers = providers;
356
this.defaultOnError = defaultOnError;
357
}
358
359
@Override
360
public boolean isEndpointDiscoveryEnabled() {
361
for (EndpointDiscoveryProvider provider : providers) {
362
try {
363
return provider.isEndpointDiscoveryEnabled();
364
} catch (Exception e) {
365
// Log error and try next provider
366
System.err.println("Endpoint discovery provider failed: " + e.getMessage());
367
}
368
}
369
370
// All providers failed, return default
371
return defaultOnError;
372
}
373
374
@Override
375
public void refresh() {
376
for (EndpointDiscoveryProvider provider : providers) {
377
try {
378
provider.refresh();
379
} catch (Exception e) {
380
// Log error but continue with other providers
381
System.err.println("Failed to refresh endpoint discovery provider: " + e.getMessage());
382
}
383
}
384
}
385
}
386
```
387
388
### Endpoint Discovery with Retry
389
390
```java
391
public class RetryableEndpointDiscoveryProvider extends BaseEndpointDiscoveryProvider {
392
private final EndpointDiscoveryProvider delegate;
393
private final int maxRetries;
394
private final long retryDelayMs;
395
396
public RetryableEndpointDiscoveryProvider(EndpointDiscoveryProvider delegate, int maxRetries, long retryDelayMs) {
397
this.delegate = delegate;
398
this.maxRetries = maxRetries;
399
this.retryDelayMs = retryDelayMs;
400
}
401
402
@Override
403
public boolean isEndpointDiscoveryEnabled() {
404
Exception lastException = null;
405
406
for (int attempt = 0; attempt <= maxRetries; attempt++) {
407
try {
408
return delegate.isEndpointDiscoveryEnabled();
409
410
} catch (Exception e) {
411
lastException = e;
412
413
if (attempt < maxRetries) {
414
try {
415
Thread.sleep(retryDelayMs * (attempt + 1)); // Linear backoff
416
} catch (InterruptedException ie) {
417
Thread.currentThread().interrupt();
418
throw new RuntimeException("Interrupted during retry", ie);
419
}
420
}
421
}
422
}
423
424
throw new RuntimeException("Endpoint discovery failed after " + maxRetries + " retries", lastException);
425
}
426
}
427
```
428
429
## Monitoring and Observability
430
431
### Endpoint Discovery Metrics
432
433
```java
434
public class MetricsEnabledEndpointDiscoveryProvider extends BaseEndpointDiscoveryProvider {
435
private final EndpointDiscoveryProvider delegate;
436
private final AtomicLong enabledCount = new AtomicLong();
437
private final AtomicLong disabledCount = new AtomicLong();
438
private final AtomicLong errorCount = new AtomicLong();
439
440
public MetricsEnabledEndpointDiscoveryProvider(EndpointDiscoveryProvider delegate) {
441
this.delegate = delegate;
442
}
443
444
@Override
445
public boolean isEndpointDiscoveryEnabled() {
446
try {
447
boolean enabled = delegate.isEndpointDiscoveryEnabled();
448
449
if (enabled) {
450
enabledCount.incrementAndGet();
451
} else {
452
disabledCount.incrementAndGet();
453
}
454
455
return enabled;
456
457
} catch (Exception e) {
458
errorCount.incrementAndGet();
459
throw e;
460
}
461
}
462
463
// Expose metrics
464
public long getEnabledCount() { return enabledCount.get(); }
465
public long getDisabledCount() { return disabledCount.get(); }
466
public long getErrorCount() { return errorCount.get(); }
467
468
public void resetMetrics() {
469
enabledCount.set(0);
470
disabledCount.set(0);
471
errorCount.set(0);
472
}
473
}
474
```
475
476
### Logging Endpoint Discovery Activity
477
478
```java
479
public class LoggingEndpointDiscoveryProvider extends BaseEndpointDiscoveryProvider {
480
private static final Logger logger = LoggerFactory.getLogger(LoggingEndpointDiscoveryProvider.class);
481
private final EndpointDiscoveryProvider delegate;
482
private final String providerName;
483
484
public LoggingEndpointDiscoveryProvider(EndpointDiscoveryProvider delegate, String providerName) {
485
this.delegate = delegate;
486
this.providerName = providerName;
487
}
488
489
@Override
490
public boolean isEndpointDiscoveryEnabled() {
491
logger.debug("Checking endpoint discovery status with provider: {}", providerName);
492
493
try {
494
boolean enabled = delegate.isEndpointDiscoveryEnabled();
495
logger.info("Endpoint discovery {} via provider: {}",
496
enabled ? "ENABLED" : "DISABLED", providerName);
497
return enabled;
498
499
} catch (Exception e) {
500
logger.error("Endpoint discovery check failed for provider: {}", providerName, e);
501
throw e;
502
}
503
}
504
505
@Override
506
public void refresh() {
507
logger.debug("Refreshing endpoint discovery provider: {}", providerName);
508
try {
509
delegate.refresh();
510
logger.debug("Successfully refreshed endpoint discovery provider: {}", providerName);
511
} catch (Exception e) {
512
logger.error("Failed to refresh endpoint discovery provider: {}", providerName, e);
513
throw e;
514
}
515
}
516
}
517
```
518
519
## Best Practices
520
521
### Configuration Best Practices
522
523
1. **Use environment-specific settings** - Different configurations for dev/staging/production
524
2. **Implement proper fallbacks** - Always provide a default configuration
525
3. **Cache results appropriately** - Avoid excessive configuration lookups
526
4. **Monitor endpoint discovery usage** - Track when discovery is enabled/disabled
527
528
### Performance Considerations
529
530
1. **Cache endpoint discovery results** to avoid repeated configuration lookups
531
2. **Use reasonable timeouts** for external configuration sources
532
3. **Implement circuit breakers** for unreliable configuration sources
533
4. **Consider the impact on cold start times** in serverless environments
534
535
### Security Considerations
536
537
1. **Validate configuration sources** to prevent configuration injection
538
2. **Use secure channels** for external configuration retrieval
539
3. **Implement proper access controls** for configuration management
540
4. **Audit endpoint discovery configuration changes**
541
542
### Testing Strategies
543
544
1. **Test with discovery enabled and disabled** in different environments
545
2. **Verify fallback behavior** when providers fail
546
3. **Test configuration refresh scenarios**
547
4. **Monitor endpoint discovery metrics** in production
548
549
Endpoint discovery provides automatic service endpoint optimization, improving performance and reliability by directing traffic to the most appropriate service endpoints based on current network conditions and service topology.