smallrye / smallrye-stork

SmallRye Stork is a service discovery and client side-load balancing framework.

Home Page:http://smallrye.io/smallrye-stork/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Programmatic service definition

vsevel opened this issue · comments

The purpose of this enhancement is to be able to define a Service programmatically, as if it had been defined in configuration. This will allow to handle dynamic use cases where the service definitions is only known at run time, or cannot be defined statically in the configuration.

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String programmatic(@PathParam("country") String country) {
        Map<String, String> params = new HashMap<>();
        params.put("stork.service.discovery.clock-" + country, "my-disc");
        params.put("stork.service.discovery.clock-" + country + ".country", country);
        Stork.getInstance().defineServiceIfAbsent(params);
        IClock clock = RestClientBuilder.newBuilder().baseUri(URI.create("stork://clock-" + country)).build(IClock.class);
        return "" + clock.currentTime();
    }

I'm wondering if it wouldn't be easier to use if we provided means to lazy-initialize services and to provide dynamic configuration.
This would be a larger change though, probably.

The proposed API for defining services doesn't give a great UX but does its job. Maybe we could add it in 1.1.1 and try to improve in 1.2 or 2.x?
@cescoffier @aureamunoz do you have an opinion?

@vsevel we had a discussion on it and we think something like this could work and provide a nice API for users, WDYT?

Stork.getInstance().defineIfAbsent("my-service", () -> new ServiceDefinition()
    .withLoadBalancer(new LeastResponseTimeLoadBalancerConfig().withErrorPenalty("30s"))
    .withServiceDiscovery(new KubernetesServiceDiscoveryConfig().withMasterUrl("https://example.com"))

The classes like LeastResponseTimeLoadBalancerConfig would be generated during configuration generation (with the annotation processor)

that looks very good. I like it.
LeastResponseTimeLoadBalancerConfig is different from the already generated LeastResponseTimeLoadBalancerConfiguration? why would we have another config class?

Actually, we do not have a LeastResponseTimeLoadBalancerConfiguration but LeastResponseTimeLoadBalancerProviderConfiguration. This class contains the user configuration and exposes it to the SD/LB providers. It is not "writable" (you cannot set the values). We could reuse the same, but that will make the data mutable, which is not necessarily what we want because obviously, it would induce synchronization and so on.

We could reuse the same, but that will make the data mutable, which is not necessarily what we want because obviously, it would induce synchronization and so on.

ok. yes.
seems a bit of waste to have 2 classes representing the same config object.
since the underlying data structure is a Map<String, String>, you could always clone it.
the other option would be to expand the LeastResponseTimeLoadBalancerProviderConfiguration to add builder style construction. it would look like this:

Stork.getInstance().defineIfAbsent("my-service", () -> new ServiceDefinition()
    .withLoadBalancer(new LeastResponseTimeLoadBalancerConfig.Builder().withErrorPenalty("30s").build())
    .withServiceDiscovery(new KubernetesServiceDiscoveryConfig.Builder().withMasterUrl("https://example.com").build())

I really would like to avoid builders. I'm becoming sick of them because of gRPC :-)

There is also an important aspect. One of the class is used by the SD/LB developer, the other one is general user facing. They actually may end up in different packages.

ok so whatever you think is best. the really important aspect was the defineIfAbsent+supplier approach.
a minor detail: is the Stork instance accessible through injection (I did not see a producer)?

No, it's a static accessor (Stork does not depend on CDI). That being said we can add a producer.

Would the static accessor be ok for you?

About the classes, I am still playing with multiple ideas.

Would the static accessor be ok for you?

sure. I was thinking about quarkus, from a homogeneity perspective.

I agree with you.
Stork, as a smallrye project, is not tied to Quarkus or CDI. You can use it "anywhere".

That being said, having a producer in Quarkus would make sense and, as you said, you provide a sense of homogeneity.

There is a (currently internal/hidden) stork extension in quarkus. We can make it make stork available via CDI

@vsevel See #259.

I decided that in the end, it would be better to have a single class...

looks good to me

@vsevel Still doing some improvements. If you have any ideas to make it better, let me know.

won't be able to look at it for a week and a half.

Forgot to close this issue.
The PR #259 was merged last week.