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

Revamp API and SPI #32

Merged
merged 6 commits into from
Jul 18, 2017
Merged

Conversation

heiko-braun
Copy link
Contributor

  • Refactor builder builder pattern
  • Introduce SPI delegation (using service loader)
  • Change API terms

- Introduce SPI delegation (using service loader)
- Change API terms
@heiko-braun
Copy link
Contributor Author

@Emily-Jiang @jmesnil @keilw

The PR introduces a revamped API and that I would like to use as a baseline moving forward. It uses more descriptive API terms and introduces a contract between the implementing runtime and health API using the ResponseBuilder and Response classes.

Implementors are expected to provide an implementation of SPIFactory that is used to load a ResponseBuilder implementation. From a users point of view this will become the main entry point (see Response.named()) to construct Response implementations that carry the health check response payload.

Let me know what you think.


public abstract Optional<Map<String, Object>> getAttributes();

private static <T> T find(Class<T> service) {
Copy link
Contributor

Choose a reason for hiding this comment

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

implementation detail but the SPIFactory should be cached instead of loading it from the ServiceLoader every time a ResponseBuilder is invoked.

It's reasonable to use the same SPIFactory for the whole lifetime of the application

Copy link
Contributor Author

@heiko-braun heiko-braun Jul 7, 2017

Choose a reason for hiding this comment

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

agreed, we will improve this when moving forward with this PR

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jmesnil done

Copy link
Member

Choose a reason for hiding this comment

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

The name SPIFactory is not good. ResponseResolver is a better name for it and it follows the similar name convention as config.

Copy link
Member

Choose a reason for hiding this comment

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

You need one more method setInstance so that it works in the OSGi environment. See ConfigProviderResolver.java.

try {
Iterator<T> iterator = ServiceLoader.load(service, Response.class.getClassLoader()).iterator();

if (iterator.hasNext()) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Assuming that a correct configured application has a single SPIFactory, we should check for multiple instances instead of letting the latest one that is loaded win.
(Have a look at https:/eclipse/microprofile-config/blob/master/api/src/main/java/org/eclipse/microprofile/config/spi/ConfigProviderResolver.java#L134 for a similar use case)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jmesnil Done

* The ResponseBuilder class is reserved for an extension by implementation providers.
* </p>
*/
public abstract class ResponseBuilder {
Copy link
Contributor

Choose a reason for hiding this comment

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

It'd be good to have a Response state(boolean up) method too (as proposed in #23 for the previous API).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes, once this is accepted (merged) we should add the changes

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jmesnil done

*/
public interface HealthStatus {
public interface SPIFactory {
Copy link
Contributor

@jmesnil jmesnil Jul 7, 2017

Choose a reason for hiding this comment

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

Name is generic and non-descriptive. Maybe something like ResponseBuilderFactory instead?

Copy link
Contributor Author

@heiko-braun heiko-braun Jul 7, 2017

Choose a reason for hiding this comment

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

It is intended to capture all possible SPI contracts. ResponseBuilder is currently the only one we have, but who knows?

Copy link
Contributor

Choose a reason for hiding this comment

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

If there is differents SPI contracts, I'd expect to load each through the ServiceLoader with their respective contract interface (instead of grouping them in a single SPIFactory class).
Especially is some contracts are optional and other mandatory

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes, that would work also.


public enum State { UP, DOWN }

public abstract String getName();
Copy link
Contributor

@jmesnil jmesnil Jul 7, 2017

Choose a reason for hiding this comment

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

I do not think that the name of the health check belongs to the Response.
I don't see an use case where a health check would return different names when it is called.

This may require a separate issue to discuss this but I think the name of the health check should be set on the HealthCheck. In the design document, I proposed to introduce a @Health(name) annotation to name a HealthCheck (and remove the info from the Response).

Please note that it's not clear to me what a name of a health check implies.
As far as I can tell, nothing in the spec or the API mandates uniqueness of names.
But the HTTP protocol document implies otherwise:

The JSON response MUST contain the id entry specifying the name of the check, to support protocols that support external identifier (i.e. URI)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

well, it is part of the Response payload. How it's get's there is a different question. I like your proposal for @Health(name) annotations

Copy link
Contributor Author

Choose a reason for hiding this comment

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

following my above response: i think name needs to stay in Response, but can be removed from ResponseBuilder, no?

Copy link
Contributor

@jmesnil jmesnil Jul 7, 2017

Choose a reason for hiding this comment

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

After having written #34, I'm almost making my mind that is is up to the API provider to "name" the procedures when it is returning its payload.
I'm not sure we need to add the name to the Response though.
The provide MUST name the health check in the HTTP payload but it is its responsibility to give it an unique name (base on my proposed @Health annotation and/or using unique generated IDs to take into account multiple deployments).

Implementation-wise it seems to be trickier to add the name to the Response from the ResponseBuilder instead of waiting to create the HTTP payload to do that.
At that point, I have access to all health check procedures and I can ensure uniqueness among their names.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I would suggest we move this to a separate thread (issue), wdyt? I'd prefer to consolidate the API first and then enhance it, a piece meal approach.

Copy link
Contributor

Choose a reason for hiding this comment

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

+1 to move it to another issue (#34 can be used for this)

@heiko-braun
Copy link
Contributor Author

@jmesnil Do you see anything else that would hold back merging this PR?

@Emily-Jiang Any thoughts on this?

Copy link
Contributor

@jmesnil jmesnil left a comment

Choose a reason for hiding this comment

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

looks good to me


public abstract Optional<Map<String, Object>> getAttributes();

private static <T> T find(Class<T> service) {
Copy link
Member

Choose a reason for hiding this comment

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

The name SPIFactory is not good. ResponseResolver is a better name for it and it follows the similar name convention as config.


public abstract Optional<Map<String, Object>> getAttributes();

private static <T> T find(Class<T> service) {
Copy link
Member

Choose a reason for hiding this comment

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

You need one more method setInstance so that it works in the OSGi environment. See ConfigProviderResolver.java.


public abstract Response state(boolean up);


Copy link
Member

Choose a reason for hiding this comment

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

You need a build() method to create a response object. Delete all the up, down and state, which should belong to Response.java.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@Emily-Jiang let's address this in a separate PR

public interface SPIFactory {

ResponseBuilder createResponseBuilder();

Copy link
Member

Choose a reason for hiding this comment

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

I think the structure is confusing. You need Response, Response Builder and ResponseResolver. ResponseResolver is to use service loader pattern to load an implementation of ResponseResolver. Response should just be a clean object to contain name, attributes, up, down, state etc.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@Emily-Jiang let's address this in a separate PR

Copy link
Member

Choose a reason for hiding this comment

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

@heiko-braun This whole PR is misleading. The structure is incorrect in my view. I would rather redo this PR instead of moving to a different PR. You can close this PR but not commit it and start a new one if you like.

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 your point of view @Emily-Jiang. However @jmesnil and I think differently and hence I've decided to merge this PR. Feel free to submit proposals based on the the new API and we take it from there.

@heiko-braun heiko-braun merged commit 2fd6713 into eclipse:master Jul 18, 2017
@jmesnil jmesnil mentioned this pull request Aug 1, 2017
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.

3 participants