DynamoDbResolveEndpointInterceptor re-evaluates endpoint rules engine on every request even when endpointOverride is static
- Dominant language
- Java
- Stars
- 2.6k
- Forks
- 1k
- Avg merge
- 2d 9h
- Merged PRs (30d)
- 51
Description
## Summary
When `DynamoDbClientBuilder.endpointOverride(uri)` is configured, the resolved endpoint is static for the lifetime of the client. However, `DynamoDbResolveEndpointInterceptor.modifyRequest()` still calls `DefaultDynamoDbEndpointProvider.resolveEndpoint()` on every single request, which re-evaluates the full endpoint rules engine and re-parses the URI from scratch each time.
## Evidence
Using async-profiler on a JanusGraph server with a DynamoDB-heavy read workload (Query-dominated, ~thousands of DynamoDB calls/sec, SDK version **2.42.28**):
- `DynamoDbResolveEndpointInterceptor.modifyRequest`: **1.97% cumulative CPU** of total JVM CPU
- `java/net/URI$Parser.scan`: **0.36% flat CPU** — URI re-parsed on every request
- `DefaultDynamoDbEndpointProvider.resolveEndpoint()` runs the full rules engine even when the endpoint was statically configured
This is a subset of the broader `AwsExecutionContextBuilder.invokeInterceptorsAndCreateExecutionContext` overhead (6.44% total).
## Workaround
Bypassing `endpointOverride` in favor of a custom `endpointProvider` lambda that returns a pre-built static `Endpoint` eliminates this per-request cost entirely:
```java
URI resolvedEndpoint = URI.create("https://dynamodb.us-east-1.amazonaws.com");
Endpoint staticEndpoint = Endpoint.builder().url(resolvedEndpoint).build();
DynamoDbClient.builder()
.endpointProvider(params -> CompletableFuture.completedFuture(staticEndpoint))
// ... rest of config
.build();
```
This saves ~0.5% CPU on our workload. The workaround is not obvious and shouldn't be required — `endpointOverride` is a documented, common configuration pattern.
## Proposed fix
When `endpointOverride` is set at client construction time, the `DynamoDbResolveEndpointInterceptor` (or the underlying `DefaultDynamoDbEndpointProvider`) should cache the resolved `Endpoint` after the first evaluation and return the cached result on subsequent requests. Since the endpoint override URI is immutable after construction, this is safe.
Alternatively, the interceptor could detect at construction time that `endpointOverride` is present and substitute a no-op/cached implementation.
## Relationship to PR #6820
PR #6820 ("Move endpoint resolution from interceptors to pipeline stage") addresses this architecturally. This issue is filed to track the specific user-visible problem — static `endpointOverride` causing per-request endpoint rules evaluation — in case the PR takes time to land or a targeted fix is preferred.
Contributor guide
Assessment
This issue has not been assessed yet.