Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make RequestContextExtension.hook() public API #5107

Merged
merged 33 commits into from
Oct 23, 2023
Merged

Conversation

my4-dev
Copy link
Contributor

@my4-dev my4-dev commented Aug 9, 2023

Motivation:

Please refer to #4991

Modifications:

  • Third-party libraries or users could use hook method to implement custom instrumentation for Armera servers or clients.

Result:

WebClient
  .builder()
  // `contextHook` should be attached when a new ClientRequestContext is created.
  .contextHook(contextHook)
  ...
  .build();

Server
  .builder()
  // `contextHook` should be attached when a new ServiceRequestContext is created.
  .contextHook(contextHook)
  ...
  .route().path("/api/...")
          .contextHook(serviceContextHook)
          .build(service)
  .build();

@ikhoon ikhoon added this to the 1.26.0 milestone Aug 10, 2023
@@ -373,6 +375,9 @@ private void handleRequest(ChannelHandlerContext ctx, DecodedHttpRequest req) th
req, sslSession, proxiedAddresses, clientAddress, remoteAddress, localAddress,
req.requestStartTimeNanos(), req.requestStartTimeMicros());

reqCtx.hook(serviceCfg.contextHook());
reqCtx.hook(config.contextHook());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we move these to the constructor of DefaultServiceRequestContext

channel, req, proxiedAddresses, clientAddress, remoteAddress, localAddress, routingCtx);

reqCtx.hook(config.contextHook());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can remove this line because the request is not exposed to users and no context is pushed.

@@ -260,6 +262,17 @@ public AbstractClientOptionsBuilder endpointRemapper(
return option(ClientOptions.ENDPOINT_REMAPPER, endpointRemapper);
}

/**
* Sets the {@link AutoCloseable} which will be called whenever this {@link RequestContext} is popped
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not set an AutoCloseable but set a Supplier which produces an AutoCloseable. Should we update the Javadoc to reflect the actual behavior correctly?

@Override
public ServiceConfigSetters contextHook(Supplier<? extends AutoCloseable> contextHook) {
requireNonNull(contextHook, "contextHook");
this.contextHook = contextHook;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we make this API take multiple contextHook like NonWrappingRequestContext.hook()?

@@ -348,7 +358,8 @@ ServiceConfig build(ServiceNaming defaultServiceNaming,
multipartUploadsLocation != null ? multipartUploadsLocation : defaultMultipartUploadsLocation,
ImmutableList.copyOf(shutdownSupports),
mergeDefaultHeaders(virtualHostDefaultHeaders.toBuilder(), defaultHeaders.build()),
requestIdGenerator != null ? requestIdGenerator : defaultRequestIdGenerator, errorHandler);
requestIdGenerator != null ? requestIdGenerator : defaultRequestIdGenerator, errorHandler,
contextHook != null ? contextHook : () -> (AutoCloseable) () -> {});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we create singleton NOOP_CONTEXT_HOOK so that RequestContext.hook(Supplier) ignore that?

class {
  public void hook(Supplier<? extends AutoCloseable> contextHook) {
    if (contextHook == NOOP_CONTEXT_HOOK) {
      return;
    }
    ...
  }
}

@my4-dev
Copy link
Contributor Author

my4-dev commented Aug 12, 2023

@ikhoon : Thanks for the advice!
I've fixed codes according to your comments.

@codecov
Copy link

codecov bot commented Sep 28, 2023

Codecov Report

Attention: 19 lines in your changes are missing coverage. Please review.

Comparison is base (96f496d) 74.07% compared to head (687bd8b) 74.03%.
Report is 6 commits behind head on main.

Additional details and impacted files
@@             Coverage Diff              @@
##               main    #5107      +/-   ##
============================================
- Coverage     74.07%   74.03%   -0.05%     
- Complexity    20012    20013       +1     
============================================
  Files          1718     1718              
  Lines         73699    73753      +54     
  Branches       9383     9387       +4     
============================================
+ Hits          54596    54604       +8     
- Misses        14662    14704      +42     
- Partials       4441     4445       +4     
Files Coverage Δ
...p/armeria/client/AbstractClientOptionsBuilder.java 98.00% <100.00%> (+0.10%) ⬆️
...ava/com/linecorp/armeria/client/ClientOptions.java 84.61% <100.00%> (+0.45%) ⬆️
.../com/linecorp/armeria/client/WebClientBuilder.java 74.35% <100.00%> (+0.67%) ⬆️
...va/com/linecorp/armeria/common/RequestContext.java 74.24% <ø> (ø)
...a/internal/client/DefaultClientRequestContext.java 90.86% <100.00%> (ø)
.../internal/server/DefaultServiceRequestContext.java 86.33% <100.00%> (ø)
.../armeria/server/AbstractServiceBindingBuilder.java 69.73% <100.00%> (+0.81%) ⬆️
...rp/armeria/server/DefaultServiceConfigSetters.java 84.12% <100.00%> (+0.65%) ⬆️
...com/linecorp/armeria/server/HttpServerHandler.java 79.20% <100.00%> (ø)
...ava/com/linecorp/armeria/server/ServerBuilder.java 82.99% <100.00%> (+0.09%) ⬆️
... and 19 more

... and 36 files with indirect coverage changes

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Member

@minwoox minwoox left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! Left some suggestions. 😉

@ikhoon
Copy link
Contributor

ikhoon commented Oct 13, 2023

We are about to release the next version. Let me address other folks' comments to add this feature to the next release.

Copy link
Member

@minwoox minwoox left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot, @my4-dev and @ikhoon! 🙌 🙌 🙌

Copy link
Member

@minwoox minwoox left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot, @my4-dev and @ikhoon! 🙌 🙌 🙌

Copy link
Member

@trustin trustin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent work, @my4-dev! 👍 Thanks for fixing a few QoL issues in our code base as well! Left a few minor comments, which could be addressed by @minwoox before he merges this PR in.

@@ -85,7 +87,7 @@ public static void init() { /* no-op */ }
/**
* Returns the {@link SafeCloseable} which doesn't do anything.
*/
@MustBeClosed
@SuppressWarnings("MustBeClosedChecker")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🙇

Comment on lines +48 to +53
assertThat(overriddenMethods)
.as("%s is not overridden by %s", method, clazz)
.filteredOn(tMethod -> {
return method.getName().equals(tMethod.getName()) &&
Arrays.equals(method.getParameterTypes(), tMethod.getParameterTypes());
}).hasSize(1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🙇

Copy link
Contributor

@ikhoon ikhoon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, @my4-dev! 🙇‍♂️🙇‍♂️

@minwoox minwoox merged commit 87f2318 into line:main Oct 23, 2023
15 checks passed
Copy link
Contributor

@jrhee17 jrhee17 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was leaving some comments, but at the very least I think the following should be addressed.

Let me upload a separate PR

@@ -172,6 +172,11 @@ public WebClientBuilder endpointRemapper(
return (WebClientBuilder) super.endpointRemapper(endpointRemapper);
}

@Override
public WebClientBuilder contextHook(Supplier<? extends AutoCloseable> contextHook) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably need to override the rest of the methods

e.g.

RestClient.builder()
          .contextHook(() -> {})
          .build();

minwoox pushed a commit that referenced this pull request Oct 25, 2023
Motivation:

I found some overridden methods were missed. #5107 (comment)
While I was at it, I also fixed a test which goes through the entire classpath looking for builders ending with the String `Builder`.

Modifications:

- Fixed `OverriddenBuilderMethodsReturnTypeTest` to not ignore missing methods
- Fixed not overridden methods

Result:

- A more consistent fluent API experience

<!--
Visit this URL to learn more about how to write a pull request description:
https://armeria.dev/community/developer-guide#how-to-write-pull-request-description
-->
Bue-von-hon pushed a commit to Bue-von-hon/armeria that referenced this pull request Nov 10, 2023
Motivation:

Please refer to line#4991

Modifications:

- Third-party libraries or users could use hook method to implement custom instrumentation for Armera servers or clients.

Result:

- Closes line#4991
- Third-party libraries or users could use contextHook method to add hook which is invoked whenever a `RequestContext` is popped from the `RequestContextStorage` like the following. 
```java
WebClient
  .builder()
  // `contextHook` should be attached when a new ClientRequestContext is created.
  .contextHook(contextHook)
  ...
  .build();

Server
  .builder()
  // `contextHook` should be attached when a new ServiceRequestContext is created.
  .contextHook(contextHook)
  ...
  .route().path("/api/...")
          .contextHook(serviceContextHook)
          .build(service)
  .build();
```

<!--
Visit this URL to learn more about how to write a pull request description:
https://armeria.dev/community/developer-guide#how-to-write-pull-request-description
-->
Bue-von-hon pushed a commit to Bue-von-hon/armeria that referenced this pull request Nov 10, 2023
Motivation:

I found some overridden methods were missed. line#5107 (comment)
While I was at it, I also fixed a test which goes through the entire classpath looking for builders ending with the String `Builder`.

Modifications:

- Fixed `OverriddenBuilderMethodsReturnTypeTest` to not ignore missing methods
- Fixed not overridden methods

Result:

- A more consistent fluent API experience

<!--
Visit this URL to learn more about how to write a pull request description:
https://armeria.dev/community/developer-guide#how-to-write-pull-request-description
-->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Make RequestContextExtension.hook() public API
5 participants