These are chat archives for spring-cloud/spring-cloud

25th
Jun 2018
Harshali Raka
@HarshaliRaka
Jun 25 2018 07:01
Does anyone know a way for Eureka-client application to be able to register to multiple Eureka servers? I tried mentioning a commaDelimited List of eureka servers for defaultZone but that doesn't seem to work. This has been mentioned here as well - https://stackoverflow.com/questions/28454916/spring-cloud-eureka-client-to-multiple-eureka-servers .
Marcos Barbero
@marcosbarbero
Jun 25 2018 07:03
It’s not meant to be like that. You should configure multiple zones for the same client instead of multiple eureka server peers
Harshali Raka
@HarshaliRaka
Jun 25 2018 07:12
Actually those eureka servers aren't peers. I'm trying to mark one eureka server as blue and the newer one green, I do not want any traffic to flow to my Green one till I have run the test suite. Only when everything passes, I want to move traffic to the new one. For that purpose would like my client app to register to both the blue and the green server.
FYI, my eureka server runs with Zuul.
Marcos Barbero
@marcosbarbero
Jun 25 2018 07:19
Do you have any code to share?
As long as you add the eureka servers as a comma delimited list in the client configuration. For the client perspective they are just peers.
If you have any code to share please do, will be easier to understand what you did and what you are actually trying to achieve
Tyler Van Gorder
@tkvangorder
Jun 25 2018 15:17
@HarshaliRaka The use case seems a little odd, rather than having separate, non-peer Eureka servers, you might want to explore adding your environment to the Eureka meta-data (when you registered each service) and then you can build custom logic in a ServerListFilter (on the client) to filter out servers by environment. We have done something similar in our environment but I will warn you that you are in for a quite a bit of work and testing.
Harshali Raka
@HarshaliRaka
Jun 25 2018 16:16
@tkvangorder Can you share ServerListFilter code for reference? This filter will just filter servers from the list but the client won't be able to connect to all the filtered servers at once, right?
KaijuDeluxe
@KaijuDeluxe
Jun 25 2018 16:41
what is best way to consume rest service which give json with nested objects? RestTemplate or anything else?
Nicolas Widart
@nWidart
Jun 25 2018 17:48

Hello, I'm having an issue trying to setup spring cloud eureka on an application which uses postgres. Since I've added eureka, I'm getting the following error on boot:

2018-06-25 18:22:31.229 ERROR 7862 --- [ost-startStop-1] o.s.b.web.embedded.tomcat.TomcatStarter  : Error starting Tomcat context. Exception: org.springframework.beans.factory.BeanCreationException. Message: Error creating bean with name 'servletEndpointRegistrar' defined in class path resource [org/springframework/boot/actuate/autoconfigure/endpoint/web/ServletEndpointManagementContextConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.actuate.endpoint.web.ServletEndpointRegistrar]: Factory method 'servletEndpointRegistrar' threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'healthEndpoint' defined in class path resource [org/springframework/boot/actuate/autoconfigure/health/HealthEndpointConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.actuate.health.HealthEndpoint]: Factory method 'healthEndpoint' threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.boot.actuate.autoconfigure.jdbc.DataSourceHealthIndicatorAutoConfiguration': Bean instantiation via constructor failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.actuate.autoconfigure.jdbc.DataSourceHealthIndicatorAutoConfiguration$$EnhancerBySpringCGLIB$$f4aa1064]: Constructor threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource': Post-processing of FactoryBean's singleton object failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Hikari.class]: Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.boot.autoconfigure.jdbc.DataSourceInitializerInvoker': Invocation of init method failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource': Post-processing of FactoryBean's singleton object failed; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'scopedTarget.dataSource': Requested bean is currently in creation: Is there an unresolvable circular reference?

In two other services where I've setup eureka no such issue. Did I miss something?

Nicolas Widart
@nWidart
Jun 25 2018 17:56
image.png
I've pinpointed the issue to this class, but I'm not sure why only with spring cloud and not before
Tyler Van Gorder
@tkvangorder
Jun 25 2018 18:16

@HarshaliRaka There are two parts to the solution, your servers can register addition information in their meta-data (like the environment they belong too), zones, etc. This is an example of what that might look like:


    @Bean
    @RefreshScope
    @Primary
    public EurekaInstanceConfigBean eurekaInstanceConfiguration(InetUtils inetUtils) {
        EurekaInstanceConfigBean instance = new EurekaInstanceConfigBean(inetUtils);
        instance.setNonSecurePort(this.nonSecurePort);
        //This method adds additional meta-data to be pushed out to Eureka when the instance registers.
        Map<String, String> metaData = instance.getMetadataMap();

        metaData.put(METADATA_VERSION_KEY, applicationVersion);
        metaData.put(METADATA_ENVIRONMENT_KEY, environment);
        metaData.put(METADATA_ZONE_KEY, primaryZone);
        metaData.put(METADATA_SECONDARY_ZONE_KEY, secondaryZone);
.
.
.

On the client side:

You can define a custom server list filter as part of your ribbon client configuration (in this example we provide a list of environments to filter by):

    @Bean 
    public ServerListFilter<?> serverListFilter() {

        return new MultiEnvironmentServerListFilter(filterEnvironments);
    }

And in the filter you can limit the servers that will be passed to Ribbon for load-balancing:

public class MultiEnvironmentServerListFilter extends AbstractServerListFilter<DiscoveryEnabledServer> implements BuildCloudConstants {


    private List<String> environments;

    public BuildMultiEnvironmentServerListFilter(List<String> filterEnvironments) {
        super();
        this.environments = filterEnvironments;
        Assert.isTrue(environments != null, "Configuration Error :: Server Filter Environments Must not be null");
        Assert.isTrue(!environments.isEmpty(), "Configuration Error :: Server Filter Environments Must not be empty");
    }

    @Override
    public List<DiscoveryEnabledServer> getFilteredListOfServers(List<DiscoveryEnabledServer> servers) {
        return servers.stream().filter(a -> this.isValid(a)).collect(Collectors.toList());
    }

    /**
     * Return true if the server belongs to any of the defined environments.
     *
     * @param server Server instance.
     * @return True if the server should be available to the client.
     */
    protected boolean isValid(DiscoveryEnabledServer server) {
        if (server == null || server.getInstanceInfo() == null) {
            logger.error(String.format("The server instance information was null. :: %s", server));
            return false;
        }

        Map<String,String> metaData = server.getInstanceInfo().getMetadata();
        if (metaData == null) {
            logger.error(String.format("The server meta-data information was null. :: %s", server));
            return false;
        }

        String lEnvironment = metaData.get(METADATA_ENVIRONMENT_KEY);
        if (lEnvironment == null) {
            logger.error(String.format("The server [%s] instance information was registered without it's environment set.", server.getInstanceInfo().getId()));
            return false;
        }

        for (String environment : environments) {
            if (environment.equalsIgnoreCase(lEnvironment)) {
                return true;
            }
        }

        return false;
    }

You can then use refreshable configuration to change which servers are going to used by your clients. Cautionary tale....if you do decide to roll your own logic for server filtering, you may be opening yourself up to quite a bit more work.