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

MP REST Client config #17220

Merged
merged 6 commits into from Sep 30, 2021
Merged

Conversation

TomasHofman
Copy link
Contributor

@TomasHofman TomasHofman commented May 14, 2021

This exposes following configuration options via the application.properties file:

org.acme.rest.client.CountriesService/mp-rest/connectionTTL
org.acme.rest.client.CountriesService/mp-rest/maxPooledPerRoute
org.acme.rest.client.CountriesService/mp-rest/connectionCheckoutTimeout
org.acme.rest.client.CountriesService/mp-rest/connectionPoolSize

(Assume org.acme.rest.client.CountriesService is an MP rest client interface.)

This could help with connection pooling issues like #15383.

AFAIK the only other way to set above properties is via registering a RestClientBuilderListener like the one bellow, but I didn't find it documented anywhere. Being able to configure those via application.properties would be more developer friendly.

public class CustomRestClientBuilderListener implements RestClientBuilderListener {

    @Override
    public void onNewBuilder(RestClientBuilder builder) {
        builder.property("resteasy.connectionTTL", Arrays.asList(2345L, TimeUnit.MILLISECONDS));
        builder.property("resteasy.maxPooledPerRoute", 1);
    }
}

@gsmet
Copy link
Member

gsmet commented May 25, 2021

@michalszynkiewicz could you have a look at this one? It looks like a worthwhile addition.

@TomasHofman
Copy link
Contributor Author

I can add a test case to this if needed. I wanted to get some feedback or review before working on it more, to make sure that the idea of adding those config parameters is OK.

@kenfinnigan
Copy link
Member

kenfinnigan commented Jun 2, 2021

Not sure what @radcortez thinks, my only concern would be around the namespacing with the /mp-rest/ prefix to the keys.

Configuration off that prefix is defined in the MicroProfile REST Client spec. As what is being proposed is not part of the spec, we should probably include them in a different way.

@TomasHofman
Copy link
Contributor Author

Thanks for feedback. Would .../restclient/... make more sense then?

@gsmet
Copy link
Member

gsmet commented Jun 2, 2021

That is going to be very confusing.

I always thought we should have used proper Quarkus config for this.

@radcortez
Copy link
Member

That is going to be very confusing.

I always thought we should have used proper Quarkus config for this.

Hum... how about if we also use quarkus? The mp-rest subnamespace is reserved for MP only config to not clash with specific runtime config and we can add what we want into the quarkus one. Of course, we can also expose all the current mp-rest configuration in the quarkus one.

So in essense:

  • mp-rest only MP standard configuration
  • quarkus every mp-rest configuration, plus specific things

May probably be worthwhile to define a specific vendor namespace in the MP Rest Client spec.

@kenfinnigan
Copy link
Member

I agree it makes sense to have a configuration key that isn't tied to the current MP way of defining REST Client config

@TomasHofman
Copy link
Contributor Author

@radcortez do I understand correctly that we would keep the class name prefix for both options?

So we would have:

org.acme.rest.client.CountriesService/mp-rest/url=http://localhost:8080/
# etc...

and then also:

org.acme.rest.client.CountriesService/quarkus/url=http://localhost:8080/
org.acme.rest.client.CountriesService/quarkus/connectionTTL=2000
org.acme.rest.client.CountriesService/quarkus/maxPooledPerRoute=3
# etc...

@radcortez
Copy link
Member

Yes, that is the proposal. We probably need a few +1 before actually going for it. @michalszynkiewicz what do you think?

@kenfinnigan
Copy link
Member

We'd duplicate the url?

@TomasHofman
Copy link
Contributor Author

From @radcortez's message:

So in essense:

  • mp-rest only MP standard configuration
  • quarkus every mp-rest configuration, plus specific things

I gather the quarkus namespace would expose everything that mp-rest exposes? :)

@kenfinnigan
Copy link
Member

Wouldn't be confusing for Quarkus to duplicate all the MP specific config?

@radcortez
Copy link
Member

We can just relocate the configuration and have quarkus to take priority and fallback to mp-rest.

I'm not sure which one is more confusing. If having to use two namespaces, or use quarkus for everything. From my perspective, I think that if you could set everything on quarkus it would be cleaner. You don't have to guess which property goes where.

But I would like to hear other thoughts.

@xstefank
Copy link
Contributor

xstefank commented Jun 7, 2021

I agree that duplicating is probably not a good idea. Just keep the custom properties under the different namespace.

@radcortez
Copy link
Member

I think we all agree on the new properties going to the Quarkus namespace, just not about the duplication. We can probably more like this and duplicate them later if needed.

BTW, another thought I had about this is, when we do an implementation first, and configurations get moved into the spec, they are renamed, but the implementation always retains the original names. In here we are doing the other way around. So what happens if one of the new configurations ends up in the specification? We are going to have spec only configurations, like we have now, quarkus only configurations, and maybe some that are on both spec and quarkus namespaces, but you will have to guess which ones.

@kenfinnigan
Copy link
Member

Another aspect is that we need to replicate these new configurations in the RESTEasy Reactive Client, not just the original client.

@michalszynkiewicz
Copy link
Member

michalszynkiewicz commented Jun 8, 2021

What's the reason for creating a separate namespace than mp-rest? Are we afraid that at some point properties with the same name (and different meaning) will be introduced in MicroProfile Rest Client?

If we want to have a separate thing from mp-rest, I don't like quarkus for the name of the namespace. For me it should be something like rest-client, rest, quarkus-rest; quarkus-rest-client if we want to be really verbose.

If we're going to have custom properties under a new namespace, I'd be in favor of having all the properties under the new namespace, and quarkus-specific namespace always winning with MicroProfile ones if duplicated. IMO, we should then advertise the new namespace only. Pro: we get a consistent way of configuring clients, con: documenting MicroProfile stuff becomes a bit more tricky.

I'm really not convinced having a separate namespace is the way to go. But if we go this way, and advertise it for all properties, it may shield us from potential namespace change when/if MicroProfile Rest Client moves to Jakarta Rest

@TomasHofman
Copy link
Contributor Author

Another aspect is that we need to replicate these new configurations in the RESTEasy Reactive Client, not just the original client.

Thanks for pointing this out. I briefly looked at the reactive client and it looks it tries to appear the same to developer (do everything as you would with the classic rest client), but naturally it uses different tech under the hood (vertx). The vertx HTTP client offers different configuration options from the Resteasy one. E.g. there is no "connectionTTL" property in vertx, but there is the "keepAliveTimeout" property, which I assume provides similar functionality (but I didn't have time to test it yet).

Now there the question how to approach this:

  1. Provide unified configuration options across both clients, which could be problematic if we want to expose something which is only available in one of the implementations.
  2. Provide different config options for each client, which might ask for separate config namespaces?

From my brief investigation (I might be wrong), only two of the four config options I wanted to expose have equivalent in VertX:

connectionTTL ~ keepAliveTimeout
maxPooledPerRoute ~ no equivalent in vertx
connectionCheckoutTimeout ~ no equivalent in vertx
connectionPoolSize ~ maxPoolSize

The only "very important" attribute of those four is "connectionTTL" / "keepAliveTimeout" (because it's needed to overcome the problem with load balancers/proxies using a shorter timeout), the others are just hitching a ride. So if I wanted to simplify as much as possible, I'm OK with exposing this one, call it "connectionTTL" for both clients and use the same namespace. This might work until we realize another attribute is needed.

@TomasHofman
Copy link
Contributor Author

TomasHofman commented Jun 8, 2021

There's another suggestion from @stuartwdouglas on google groups (https://groups.google.com/g/quarkus-dev/c/FtJMcrveIgA):

What about something like:

  • org.acme.rest.client.CountriesService/mp-rest/quarkus/connectionTTL
  • org.acme.rest.client.CountriesService/mp-rest/quarkus/maxPooledPerRoute
  • org.acme.rest.client.CountriesService/mp-rest/quarkus/connectionCheckoutTimeout
  • org.acme.rest.client.CountriesService/mp-rest/quarkus/connectionPoolSize

This way it is similar to the existing config, but won't conflict with any future properties that may be defined.

@radcortez
Copy link
Member

What's the reason for creating a separate namespace than mp-rest? Are we afraid that at some point properties with the same name (and different meaning) will be introduced in MicroProfile Rest Client?

Yes. I agree the chances for it to happen are slim. Maybe we are just adding complexity when there is none.

If we want to have a separate thing from mp-rest, I don't like quarkus for the name of the namespace. For me it should be something like rest-client, rest, quarkus-rest; quarkus-rest-client if we want to be really verbose.

Using rest-client sounds good. No references to any particular API or implementation.

If we're going to have custom properties under a new namespace, I'd be in favor of having all the properties under the new namespace, and quarkus-specific namespace always winning with MicroProfile ones if duplicated. IMO, we should then advertise the new namespace only. Pro: we get a consistent way of configuring clients, con: documenting MicroProfile stuff becomes a bit more tricky.

+1

I'm really not convinced having a separate namespace is the way to go. But if we go this way, and advertise it for all properties, it may shield us from potential namespace change when/if MicroProfile Rest Client moves to Jakarta Rest

So do you think we should just put any new things in mp-rest?

@stuartwdouglas
Copy link
Member

We should definitely not have split namespaces, were some stuff is under MP config and some stuff is under quarkus, this is super confusing. IMHO this is already pretty verbose as this has to be defined for every client interface, when often they will all be pointing at the same place. If we are going to offer quarkus options then IMHO we should do something like:

quarkus.rest-client.url=http://localhost:8080  #The default URL for all clients
quarkus.rest-client.beerservice.url=http://beer.com #the URL for 'beerservice' clients, as determined by an annotation

The beerservice would be something like:

@ClientGroup("beerservice")
public interface RatingService { ...

or a meta annotation:

@ClientGroup("beerservice")
public @interface BeerService {}

@BeerService
public interface RatingService {

This way we are not just duplicating the MP config, but are offering something that is IMHO much more useful and user friendly.

@michalszynkiewicz
Copy link
Member

@radcortez yes, I might be wrong but it seems to be the solution with least drawbacks to me.

@stuartwdouglas what's your opinion on adding the new properties under mp-rest?

I like the idea of trying to do better than the spec. I'm not sure though if @ClientGroup name wouldn't be a bit confusing for the users. I think using a single client for one base url is the most common case.

Side note: grouping might work (although this wasn't probably designed for it) in MP Rest Client with:

@RegisterRestClient(configKey="myClient")
public interface MyClient1 {
}

@RegisterRestClient(configKey="myClient")
public interface MyClient1 {
}

configured by:

myClient/mp-rest/url=http://beer.com

@stuartwdouglas
Copy link
Member

The only issue I have with adding new properties under mp-rest is that there is potential for conflicts, but that is probably not such a big deal.

I think for some of these settings we should be able to set global defaults as well.

@TomasHofman
Copy link
Contributor Author

Taking into account the input presented here and also a related issue #17832 (which calls for providing alternative way of configuring rest client and GraphQL, that wouldn't use slash character in config properties), I'm proposing following solution:

  • The current config schema ClassName/mp-rest/property-name would remain in place with no changes (no new properties).
  • A new schema would be created as proposed in the MP REST/GraphQL client config and slashes #17832, that would be consistent with the rest of Quarkus configuration. It can look like this:
# configuration via config key:
quarkus.rest-client.countries-service.url=https://restcountries.eu/rest
quarkus.rest-client.countries-service.scope=Singleton
# configuration via class name:
quarkus.rest-client."org.acme.rest.client.CountriesService".url=https://restcountries.eu/rest
quarkus.rest-client."org.acme.rest.client.CountriesService".scope=Singleton
  • Two new properties, connectionTTL and connectionPoolSize will be introduced into the new schema. These will be working for both the classic and reactive clients.
  • The new schema will override properties set via the old one.

This allows for grouping clients (multiple client interfaces sharing the same config) by defining the same config key in the client interfaces: @RegisterRestClient(configKey="country-service").

Copy link
Member

@radcortez radcortez left a comment

Choose a reason for hiding this comment

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

Just added a small comment in the documentation, but nothing major.

@quarkus-bot
Copy link

quarkus-bot bot commented Sep 21, 2021

This workflow status is outdated as a new workflow run has been triggered.

Failing Jobs - Building ff2ae38

Status Name Step Failures Logs Raw logs
Gradle Tests - JDK 11 Windows Build Failures Logs Raw logs
JVM Tests - JDK 11 Build Failures Logs Raw logs
JVM Tests - JDK 11 Windows Build Failures Logs Raw logs
JVM Tests - JDK 16 Build Failures Logs Raw logs
Native Tests - Data3 Build Failures Logs Raw logs

Full information is available in the Build summary check run.

Failures

⚙️ Gradle Tests - JDK 11 Windows #

- Failing: integration-tests/gradle 

📦 integration-tests/gradle

io.quarkus.gradle.devmode.MultiModuleIncludedBuildTest.main line 24 - More details - Source on GitHub

java.lang.AssertionError: 

Expecting actual:

⚙️ JVM Tests - JDK 11 #

- Failing: extensions/resteasy-reactive/rest-client-reactive/deployment 
! Skipped: docs extensions/oidc-client-reactive-filter/deployment extensions/resteasy-reactive/rest-client-reactive-jackson/deployment and 5 more

📦 extensions/resteasy-reactive/rest-client-reactive/deployment

io.quarkus.rest.client.reactive.ClassNameScopeOverrideTest. - More details - Source on GitHub

java.lang.RuntimeException: 
java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
	[error]: Build step io.quarkus.arc.deployment.ArcProcessor#validate threw an exception: javax.enterprise.inject.spi.DeploymentException: javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type io.quarkus.rest.client.reactive.HelloClient2 and qualifiers [@RestClient]

io.quarkus.rest.client.reactive.ConfigurationTest. - More details - Source on GitHub

java.lang.RuntimeException: 
java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
	[error]: Build step io.quarkus.arc.deployment.ArcProcessor#validate threw an exception: javax.enterprise.inject.spi.DeploymentException: javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type io.quarkus.rest.client.reactive.HelloClient2 and qualifiers [@RestClient]

io.quarkus.rest.client.reactive.LegacyConfigurationTest. - More details - Source on GitHub

java.lang.RuntimeException: 
java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
	[error]: Build step io.quarkus.arc.deployment.ArcProcessor#validate threw an exception: javax.enterprise.inject.spi.DeploymentException: javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type io.quarkus.rest.client.reactive.HelloClient2 and qualifiers [@RestClient]

io.quarkus.rest.client.reactive.MpClassNameScopeOverrideTest. - More details - Source on GitHub

java.lang.RuntimeException: 
java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
	[error]: Build step io.quarkus.arc.deployment.ArcProcessor#validate threw an exception: javax.enterprise.inject.spi.DeploymentException: javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type io.quarkus.rest.client.reactive.HelloClient2 and qualifiers [@RestClient]

io.quarkus.rest.client.reactive.ShortNameScopeOverrideTest. - More details - Source on GitHub

java.lang.RuntimeException: 
java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
	[error]: Build step io.quarkus.arc.deployment.ArcProcessor#validate threw an exception: javax.enterprise.inject.spi.DeploymentException: javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type io.quarkus.rest.client.reactive.HelloClient2 and qualifiers [@RestClient]

⚙️ JVM Tests - JDK 11 Windows #

- Failing: extensions/amazon-lambda/deployment extensions/resteasy-reactive/rest-client-reactive/deployment 
! Skipped: docs extensions/amazon-lambda-http/deployment extensions/amazon-lambda-rest/deployment and 13 more

📦 extensions/amazon-lambda/deployment

io.quarkus.amazon.lambda.deployment.testing.LambdaDevServicesContinuousTestingTestCase.testLambda line 41 - More details - Source on GitHub

org.opentest4j.AssertionFailedError: expected: <0> but was: <1>
	at org.junit.jupiter.api.AssertionUtils.fail(AssertionUtils.java:55)
	at org.junit.jupiter.api.AssertionUtils.failNotEqual(AssertionUtils.java:62)

📦 extensions/resteasy-reactive/rest-client-reactive/deployment

io.quarkus.rest.client.reactive.ClassNameScopeOverrideTest. - More details - Source on GitHub

java.lang.RuntimeException: 
java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
	[error]: Build step io.quarkus.arc.deployment.ArcProcessor#validate threw an exception: javax.enterprise.inject.spi.DeploymentException: javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type io.quarkus.rest.client.reactive.HelloClient2 and qualifiers [@RestClient]

io.quarkus.rest.client.reactive.ConfigurationTest. - More details - Source on GitHub

java.lang.RuntimeException: 
java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
	[error]: Build step io.quarkus.arc.deployment.ArcProcessor#validate threw an exception: javax.enterprise.inject.spi.DeploymentException: javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type io.quarkus.rest.client.reactive.HelloClient2 and qualifiers [@RestClient]

io.quarkus.rest.client.reactive.LegacyConfigurationTest. - More details - Source on GitHub

java.lang.RuntimeException: 
java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
	[error]: Build step io.quarkus.arc.deployment.ArcProcessor#validate threw an exception: javax.enterprise.inject.spi.DeploymentException: javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type io.quarkus.rest.client.reactive.HelloClient2 and qualifiers [@RestClient]

io.quarkus.rest.client.reactive.MpClassNameScopeOverrideTest. - More details - Source on GitHub

java.lang.RuntimeException: 
java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
	[error]: Build step io.quarkus.arc.deployment.ArcProcessor#validate threw an exception: javax.enterprise.inject.spi.DeploymentException: javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type io.quarkus.rest.client.reactive.HelloClient2 and qualifiers [@RestClient]

io.quarkus.rest.client.reactive.ShortNameScopeOverrideTest. - More details - Source on GitHub

java.lang.RuntimeException: 
java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
	[error]: Build step io.quarkus.arc.deployment.ArcProcessor#validate threw an exception: javax.enterprise.inject.spi.DeploymentException: javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type io.quarkus.rest.client.reactive.HelloClient2 and qualifiers [@RestClient]

⚙️ JVM Tests - JDK 16 #

- Failing: extensions/resteasy-reactive/rest-client-reactive/deployment 
! Skipped: docs extensions/oidc-client-reactive-filter/deployment extensions/resteasy-reactive/rest-client-reactive-jackson/deployment and 5 more

📦 extensions/resteasy-reactive/rest-client-reactive/deployment

io.quarkus.rest.client.reactive.ClassNameScopeOverrideTest. - More details - Source on GitHub

java.lang.RuntimeException: 
java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
	[error]: Build step io.quarkus.arc.deployment.ArcProcessor#validate threw an exception: javax.enterprise.inject.spi.DeploymentException: javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type io.quarkus.rest.client.reactive.HelloClient2 and qualifiers [@RestClient]

io.quarkus.rest.client.reactive.ConfigurationTest. - More details - Source on GitHub

java.lang.RuntimeException: 
java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
	[error]: Build step io.quarkus.arc.deployment.ArcProcessor#validate threw an exception: javax.enterprise.inject.spi.DeploymentException: javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type io.quarkus.rest.client.reactive.HelloClient2 and qualifiers [@RestClient]

io.quarkus.rest.client.reactive.LegacyConfigurationTest. - More details - Source on GitHub

java.lang.RuntimeException: 
java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
	[error]: Build step io.quarkus.arc.deployment.ArcProcessor#validate threw an exception: javax.enterprise.inject.spi.DeploymentException: javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type io.quarkus.rest.client.reactive.HelloClient2 and qualifiers [@RestClient]

io.quarkus.rest.client.reactive.MpClassNameScopeOverrideTest. - More details - Source on GitHub

java.lang.RuntimeException: 
java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
	[error]: Build step io.quarkus.arc.deployment.ArcProcessor#validate threw an exception: javax.enterprise.inject.spi.DeploymentException: javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type io.quarkus.rest.client.reactive.HelloClient2 and qualifiers [@RestClient]

io.quarkus.rest.client.reactive.ShortNameScopeOverrideTest. - More details - Source on GitHub

java.lang.RuntimeException: 
java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
	[error]: Build step io.quarkus.arc.deployment.ArcProcessor#validate threw an exception: javax.enterprise.inject.spi.DeploymentException: javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type io.quarkus.rest.client.reactive.HelloClient2 and qualifiers [@RestClient]

⚙️ Native Tests - Data3 #

- Failing: integration-tests/liquibase 

📦 integration-tests/liquibase

Failed to execute goal io.quarkus:quarkus-maven-plugin:999-SNAPSHOT:build (default) on project quarkus-integration-test-liquibase: Failed to build quarkus application

@TomasHofman
Copy link
Contributor Author

Added some test fixes after rebasing.

@quarkus-bot
Copy link

quarkus-bot bot commented Sep 21, 2021

This workflow status is outdated as a new workflow run has been triggered.

Failing Jobs - Building a09f9d2

Status Name Step Failures Logs Raw logs
✔️ JVM Tests - JDK 11
JVM Tests - JDK 16 Build ⚠️ Check → Logs Raw logs
MicroProfile TCKs Tests Verify ⚠️ Check → Logs Raw logs

@quarkus-bot
Copy link

quarkus-bot bot commented Sep 22, 2021

This workflow status is outdated as a new workflow run has been triggered.

Failing Jobs - Building c567f10

Status Name Step Failures Logs Raw logs
✔️ JVM Tests - JDK 11
JVM Tests - JDK 16 Build ⚠️ Check → Logs Raw logs

@geoand
Copy link
Contributor

geoand commented Sep 30, 2021

Can you please rebase this to make sure it still passes CI?

Sorry it wasn't merged before...

@geoand
Copy link
Contributor

geoand commented Sep 30, 2021

I actually rebased the PR myself.

@geoand geoand added the triage/waiting-for-ci Ready to merge when CI successfully finishes label Sep 30, 2021
@TomasHofman
Copy link
Contributor Author

Thanks! I will watch the results.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/dependencies Pull requests that update a dependency file area/documentation area/resteasy-reactive
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

9 participants