Add request-level MetricPublisher support to the S3 CRT client - #7316
Conversation
| * Request-level publishers (if any were set on the request override) take precedence over the client-level | ||
| * publishers; otherwise the client-level publishers are used. | ||
| */ | ||
| @SdkTestInternalApi |
There was a problem hiding this comment.
Why is it a test internal api?
There was a problem hiding this comment.
ah, good catch. These aren't test only apis. Removing all such references.
| return operation.apply(stashRequestMetricPublishers(request)); | ||
| } | ||
|
|
||
| @SdkTestInternalApi |
| long partSizeInBytes = builder.minimalPartSizeInBytes == null ? DEFAULT_PART_SIZE_IN_BYTES : | ||
| builder.minimalPartSizeInBytes; | ||
| long thresholdInBytes = builder.thresholdInBytes == null ? partSizeInBytes : builder.thresholdInBytes; | ||
| this.copyPartSizeInBytes = builder.minimalPartSizeInBytes == null ? DEFAULT_PART_SIZE_IN_BYTES : |
There was a problem hiding this comment.
Nit: though these fields are only used by copy helper, they are still general partSize and threshold, suggesting keep the original name
| * publishers. Used only by {@link #copyObject(CopyObjectRequest)} when the copy request specifies request-level | ||
| * publishers, so each copy sub-request publishes CRT telemetry to them instead of to the client-level publishers. | ||
| */ | ||
| static final class RequestMetricPublisherInjectingClient extends DelegatingS3AsyncClient { |
There was a problem hiding this comment.
Hope to confirm: this includes head/create/part-copies/complete and tagging/annotation reads and writes, this is the intended design right?
… of a per-sub-request wrapper
|
|
||
| @Test | ||
| void failedGetObject_publishesUnsuccessfulApiCallMetrics() throws InterruptedException { | ||
| try { |
There was a problem hiding this comment.
Can we use wiremock tests instead for error cases since it's more deterministic?
There was a problem hiding this comment.
Added a deterministic wiremock test in S3CrtClientWiremockTest
| } | ||
| } | ||
|
|
||
| @Test |
There was a problem hiding this comment.
Should we add assertThat(clientPublisher.awaitAtLeast(1, Duration.ofSeconds(1))).isEmpty();?
There was a problem hiding this comment.
Good catch, added.
| // The adapter reads its inputs from the execution attributes. METRIC_PUBLISHERS currently holds the | ||
| // request-level publishers (if any) the interceptor stashed; resolve them against the client-level publishers | ||
| // (request-level takes precedence) and attach the effective set here when there are any. toBuilder() preserves | ||
| // everything already in the bag (including CRT_PROGRESS_LISTENER); skip the copy entirely when no publishers | ||
| // are configured, to avoid rebuilding the bag on every request. |
There was a problem hiding this comment.
Are the comments here necessary? Seems pretty straightforward
There was a problem hiding this comment.
Agreed, removed
| } | ||
|
|
||
| private CompletableFuture<List<Tag>> fetchSourceTagging(CopyObjectRequest copyObjectRequest, String sourceVersionId) { | ||
| AwsRequestOverrideConfiguration override = copyObjectRequest.overrideConfiguration().orElse(null); |
There was a problem hiding this comment.
Added unit tests in CopyObjectHelperTest verifying the copy's override propagates to every tagging and annotation sub request - getObjectTagging/putObjectTagging and listObjectAnnotations/getObjectAnnotation/putObjectAnnotation.
ab4f33f
into
feature/master/S3CRTMetricPublisher
|
This pull request has been closed and the conversation has been locked. Comments on closed PRs are hard for our team to see. If you need more assistance, please open a new issue that references this one. |
Motivation and Context
Follow-up to the client-level MetricPublisher support (#7299). This adds request-level metric publishers to the S3 CRT-based client: a publisher attached to a single request via
overrideConfiguration(o -> o.addMetricPublisher(...))now receives that request's CRT telemetry, matching the standard S3 client. When a request sets its own publishers, they take precedence over the client-level ones for that request; an empty request-level list falls back to the client-level publishers, same as the standard client.Modifications
Request-level publishers are moved off the request's override configuration and routed to the CRT
transport, so the inner standard client stays publisher-free (no hollow, duplicate ApiCall metric) and
telemetry is published from
onTelemetry, once per underlying CRT request.DefaultS3CrtAsyncClientinvokeOperationstrips the request-level publishers off the override viastashRequestMetricPublishersand stashes them in a request execution attribute; an interceptor bridges that to the transport's SDK-HTTP attribute.copyObjectstashes once at the entry point.copyObject's sub-requests bypassinvokeOperation, so a single stash there plus the copy helper's existing override propagation carries the publishers to every sub-request, with no per-sub-request wrapper.S3CrtAsyncHttpClientresolves request-level vs client-level publishers (request-level takes precedence) and folds the effective set back into the execution attributes for the response adapter.CopyObjectHelpernow propagates the copy request's override configuration to the tagging and annotation sub-requests (GetObjectTagging/PutObjectTagging/ annotation reads and writes), which were previously built without it. This was a pre-existing gap: an override set on a copy was silently dropped for those sub-requests, so their CRT telemetry never reached a request-level publisher. All copy sub-requests (head / create / part-copies / complete, and now tagging / annotation) inherit the copy's override.Testing
S3CrtMetricPublisherResolutionTest): the resolution matrix (none / client-only / request-only / request-overrides-client) and the stash transform (for a normal operation and forcopyObject).S3CrtClientMetricPublisherIntegrationTest): client-level single-part / multipart get, put, and failed paths; request-levelgetObjectandcopyObjectpublish to the request-level publisher while the client-level one is bypassed; and a tagging-directive copy verifies itsGetObjectTaggingandPutObjectTaggingsub-requests publish to the request-level publisher, exercising theCopyObjectHelperpropagation fix end to end.Screenshots (if appropriate)
Types of changes
Checklist
mvn installsucceedsscripts/new-changescript and following the instructions. Commit the new file created by the script in.changes/next-releasewith your changes.License