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

Introduce HttpProviders and GrpcProviders #2137

Merged
merged 7 commits into from
Mar 24, 2022

Conversation

idelpivnitskiy
Copy link
Member

@idelpivnitskiy idelpivnitskiy commented Mar 9, 2022

Motivation:

Allow users to intercept static factories that create client/server
builders to enhance builders' behavior. Users can use these providers
to override default values on the builders or to intercept builders for
metrics purposes.

Modifications:

  • Add HttpProviders and GrpcProviders that define provider
    interfaces for ServiceLoader;
  • Test how users can intercept builders;

Result:

Users can change the default builders using providers that are
automatically loaded via ServiceLoader.


@Override
public GrpcClientBuilder<U, R> defaultTimeout(final Duration defaultTimeout) {
delegate = delegate.defaultTimeout(defaultTimeout);
Copy link
Member Author

Choose a reason for hiding this comment

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

When I had all builder methods as

    @Override
    public GrpcClientBuilder<U, R> defaultTimeout(final Duration defaultTimeout) {
        delegate.defaultTimeout(defaultTimeout);
        return this;
    }

Spotbugs complained that the return value is discarded. I though to suppress it because all our builder implementations always return this. But then considered a use-case when users may have an immutable provider or builder impl that always return a new instance. LMK what you think. Should we support that and reassign the delegate or is it better to keep delegate as final?

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't see any alternative to assigning delegate with each delegate invocation. Eventually someone will get clever and implement a builder which doesn't return this and we will have to fix it anyway. I've had to fix very non-obvious problems more than once where failing to reassign the builder at the end of the chain meant that the operations in the chain were lost. It is always a frustrating bug to locate.

Motivation:

Allow users intercept static factories that create client/server
builders to enhance builders behavior. Users can use these providers
to override default values on the builders or to intercept builders for
metrics purposes.

Modifications:

- Add `HttpProviders` and `GrpcProviders` that define provider
interfaces for `ServiceLoader`;
- Test how users can intercept builders;

Result:

Users can change the default builders using providers that are
automatically loaded via `ServiceLoader`.
/**
* A factory to create <a href="https://www.grpc.io">gRPC</a> clients.
*/
public final class GrpcClients {

private static final Logger LOGGER = LoggerFactory.getLogger(GrpcClients.class);

private static final List<GrpcClientBuilderProvider> PROVIDERS;
Copy link
Contributor

@bondolo bondolo Mar 17, 2022

Choose a reason for hiding this comment

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

I wonder if putting these in the GrpcProviders class and exposing a static method wouldn't also satisfy the desire for discovering what providers are installed which some users will probably want to know..

Copy link
Member Author

Choose a reason for hiding this comment

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

Let's see if logging is enough for now and defer expanding the public API surface

* @param <T> type of the provider
* @return a list of loaded providers for the specified class
*/
public static <T> List<T> loadProviders(final Class<T> clazz, final ClassLoader classLoader, final Logger logger) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Perhaps returning a Set or Collection since we don't actually support ordering and there should be no duplicate entries. We could make it an NavigableSet later if we decided to support ordering mechanism.

Copy link
Member Author

Choose a reason for hiding this comment

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

Discussed offline, posting here for visibility:
This is an internal utility.
ServiceLoader implements Iterable. Will be more predictable to follow the result of the ServiceLoader, including the order. If it decides to load multiple equal instances (not sure if this is possible), we should preserve this behavior. Also, there are no requirements for providers to implement equals/hashCode.

import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.List;

import static io.servicetalk.utils.internal.ServiceLoaderUtils.loadProviders;

/**
* Factory methods for building HTTP Servers backed by {@link ServerContext}.
Copy link
Contributor

Choose a reason for hiding this comment

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

The connection to ServerContext is not clear from reading this class.

Copy link
Member Author

Choose a reason for hiding this comment

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

Updated to make consistent with other factories.

@apple apple deleted a comment from bondolo Mar 23, 2022
@apple apple deleted a comment from bondolo Mar 23, 2022
@apple apple deleted a comment from bondolo Mar 23, 2022
@apple apple deleted a comment from bondolo Mar 23, 2022
@apple apple deleted a comment from bondolo Mar 23, 2022
@apple apple deleted a comment from bondolo Mar 23, 2022
@apple apple deleted a comment from bondolo Mar 23, 2022
@apple apple deleted a comment from bondolo Mar 23, 2022
@apple apple deleted a comment from bondolo Mar 23, 2022
@apple apple deleted a comment from bondolo Mar 23, 2022
@apple apple deleted a comment from bondolo Mar 23, 2022
@apple apple deleted a comment from bondolo Mar 23, 2022
@idelpivnitskiy
Copy link
Member Author

By some reason, comments were posted twice. I deleted duplicated comments

@idelpivnitskiy idelpivnitskiy requested a review from bondolo March 23, 2022 18:08
@idelpivnitskiy idelpivnitskiy merged commit 13107f8 into apple:main Mar 24, 2022
@idelpivnitskiy idelpivnitskiy deleted the service-loader branch March 24, 2022 22:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants