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

Untangling GrpcServerBuilder from HttpServerBuilder #1861

Merged
merged 8 commits into from
Oct 11, 2021

Conversation

chemicL
Copy link
Contributor

@chemicL chemicL commented Oct 4, 2021

Motivation:

The methods in GrpcServerBuilder are often only delegating to the
underlying HTTP transport builder. It will be beneficial if the API can
be simplified and have only gRPC specific settings. The first step is to
deprecate the methods which can be called directly on the underlying
HttpServerBuilder and to introduce a method for configuring that
builder.

Modifications:

  • Introduce a GrpcServerBuilder.HttpInitializer interface and a
    corresponding GrpcServerBuilder#initialize method which accepts the
    initializer for the underlying HttpServerBuilder instance,
  • Deprecate methods which have only served the purpose of delegating to
    the underlying HTTP transport builder,
  • Refactor tests to use the new approach to showcase it works.

Result:

The API of GrpcServerBuilder is prepared for removal of the deprecated
methods in 0.42 release and the API is more specific, while maintaining
the same level of configurability.

Motivation:

The methods in `GrpcServerBuilder` are often only delegating to the
underlying HTTP transport builder. It will be beneficial if the API can
be simplified and have only gRPC specific settings. The first step is to
deprecate the methods which can be called directly on the underlying
`HttpServerBuilder` and to introduce a method for configuring that
builder.

Modifications:

- Introduce a `GrpcServerBuilder.HttpInitializer` interface and a
  corresponding `GrpcServerBuilder#initialize` method which accepts the
  initializer for the underlying `HttpServerBuilder` instance,
- Deprecate methods which have only served the purpose of delegating to
  the underlying HTTP transport builder,
- Refactor tests to use the new approach to showcase it works.

Result:

The API of `GrpcServerBuilder` is prepared for removal of the deprecated
methods in 0.42 release and the API is more specific, while maintaining
the same level of configurability.
Copy link
Contributor

@tkountis tkountis left a comment

Choose a reason for hiding this comment

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

The deprecations will be removed for 0.42 correct?

private boolean appendedCatchAllFilter;

public abstract GrpcServerBuilder initializer(HttpInitializer initializer);
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this affect the order of applied configurations? In other words, when we are in this transient state with the deprecations, if users call appendHttpServiceFilter directly (deprecated methods) and they also start using the initializer where they also might append filters, is the order of the filters consistent to what it would have been if that new API wasn't there? If thats the case, can we prevent bad configuration, e.g. allowing exclusively one way or the other.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Great observation! To answer – the order would not be preserved as the initializer is applied at build time, while the deprecated methods have an immediate effect on the underlying builder. We could add documentation, but that would not prevent users from possible issues. I will try to implement a mutually exclusive mechanism, bear with me.

Copy link
Member

@idelpivnitskiy idelpivnitskiy Oct 5, 2021

Choose a reason for hiding this comment

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

Ok, I found where this comes from :)
We should not be extra caution in this scenario. Users either migrate all appendHttpServiceFilter methods or nothing. If they use a mixed approach - this is their problem, because we recommend migration, not mixing. We can clarify it in javadoc, but no need to add extra guards in the code. Neither multi-address nor partitioned client builders have similar guards.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's one way of looking at it. It is not always the case that users can migrate everything at the same time - say they receive a preconfigured builder from their own library and append their own configurations. In this case it's probably better to actually fail instead of being forced to debug production issues which are not straightforward to understand. I was happy with @tkountis suggestion so I implemented the validation. But I agree, a consistent approach would be to not validate the use as the other builders didn't check the state. Also, an exception is perhaps too aggressive as it might happen at runtime in a situation that is not dramatic for the user and can go past automated tests where the logic is not validated. So I decided to remove the logic. But I believe it's a matter of opinion that ServiceTalk takes -> we could as well transition into a more safe-to-use/prevent-users-from-shooting-themselves-in-the-foot approach.

@chemicL
Copy link
Contributor Author

chemicL commented Oct 5, 2021

The deprecations will be removed for 0.42 correct?

Yes, that is the intention to remove the deprecated methods.

Copy link
Contributor

@tkountis tkountis left a comment

Choose a reason for hiding this comment

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

LGTM 🚢

// been used to build a client.
if (initializer != null) {
if (underlyingBuilderCalledDirectly) {
throw new IllegalStateException("Builder configured with " + HttpInitializer.class.getName() +
Copy link
Member

Choose a reason for hiding this comment

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

Why this is a problem to mix approaches? Top level methods delegate to httpServerBuilder, initializer also invokes methods on the same httpServerBuilder. Order should not matter for most of the settings except "appendFilter", which is fine.

Copy link
Contributor Author

@chemicL chemicL Oct 7, 2021

Choose a reason for hiding this comment

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

I replied in the other thread as a general comment. Regarding order of operations -> it's not just appending filters that can be a problem.
Configuring anything else at the same time can be a surprise as the actual implementation controls the order of initializers. Consider the following code:

GrpcServers.forAddress(localAddress(0))
                .initializeHttp(builder -> builder.sslConfig(trustedServerConfig()))
                .sslConfig(untrustedServerConfig())
                .listenAndAwait(serviceFactory());

The actual SSL config will be trustedServerConfig() now and would also have been before my recent change. However the user might as well expect that the order of calls should determine the actual outcome and expect untrustedServerConfig() to be actually applied.

@bondolo bondolo added API PR with API changes (New or Deprecated) breaking-change PR with breaking changes, removed APIs or other binary incompatibilities. labels Oct 5, 2021
@idelpivnitskiy idelpivnitskiy removed the breaking-change PR with breaking changes, removed APIs or other binary incompatibilities. label Oct 5, 2021
@idelpivnitskiy
Copy link
Member

idelpivnitskiy commented Oct 5, 2021

@bondolo this is not a breaking change, we expect to cherry-pick this into 0.41

@chemicL chemicL requested a review from idelpivnitskiy October 6, 2021 15:15
Copy link
Member

@idelpivnitskiy idelpivnitskiy left a comment

Choose a reason for hiding this comment

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

LGTM after the last comments addressed.
Nice change! Thanks @tkountis for a proposal ❤️

Copy link
Member

@idelpivnitskiy idelpivnitskiy left a comment

Choose a reason for hiding this comment

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

Discovered when I reviewed the client-side:

@chemicL chemicL merged commit e892ff9 into apple:main Oct 11, 2021
chemicL pushed a commit that referenced this pull request Oct 13, 2021
Motivation:

The methods in `GrpcServerBuilder` are often only delegating to the
underlying HTTP transport builder. It will be beneficial if the API can
be simplified and have only gRPC specific settings. The first step is to
deprecate the methods which can be called directly on the underlying
`HttpServerBuilder` and to introduce a method for configuring that
builder.

Modifications:

- Introduce a `GrpcServerBuilder.HttpInitializer` interface and a
  corresponding `GrpcServerBuilder#initialize` method which accepts the
  initializer for the underlying `HttpServerBuilder` instance,
- Deprecate methods which have only served the purpose of delegating to
  the underlying HTTP transport builder,
- Added default implementations for deprecated methods,
- Made the builder reconfigurable after first build,
- Clarified javadoc for lifecycleObserver overriding by initializer,
- Refactor tests to use the new approach to showcase it works.

Result:

The API of `GrpcServerBuilder` is prepared for removal of the deprecated
methods in 0.42 release and the API is more specific, while maintaining
the same level of configurability.
@chemicL
Copy link
Contributor Author

chemicL commented Oct 13, 2021

Cherry-picked for 0.41: f8aaa8d

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
API PR with API changes (New or Deprecated)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants