spring-cloud / spring-cloud/spring-cloud-consul

Spring Cloud Consul does not work well with application context hierarchies and profiles

Open
#811 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

waiting-for-triage
Dominant language
Java
Stars
822
Forks
539
Avg merge
9h 31m
Merged PRs (30d)
7

Description

Describe the bug
Spring Cloud Consul: 3.0.4
Spring Boot: 2.5.14
Java: 11

Given the following application context hierarchy:

        final SpringApplicationBuilder parentBuilder = new SpringApplicationBuilder()
                .profiles("A")
                .web(WebApplicationType.NONE);
        parentBuilder.run(args);

        parentBuilder.child(BootstrapApplication.class)
                .web(WebApplicationType.NONE)
                .profiles("A", "B")
                .run(args)
                .close();

        parentBuilder.child(ApplicationConfiguration.class)
                .profiles("A")
                .web(WebApplicationType.SERVLET)
                .run(args);

And given that ConsulPropertySourceLocator is a singleton in the bootstrap context, when the empty parent context (parentBuilder) is loaded it's Environment contains the following ConsulPropertySource's:

0 = "config/service,A/"
1 = "config/service/"
2 = "config/application,A/"
3 = "config/application/"

This is all good and normal, but when the second context is loaded, it's Environment contains the following ConsulPropertySource's:

0 = "config/service,A/"
1 = "config/service/"
2 = "config/application,A/"
3 = "config/application/"
4 = "config/service,A/"
5 = "config/service,B/"
6 = "config/service/"
7 = "config/application,A/"
8 = "config/application,B/"
9 = "config/application/"

The problem is that the ConsulPropertySourceLocator is caching Consul context's from the previous ApplicationContext and just appending them together. And properties from the "B" profile that override properties from the "default" profile are not being picked up.

The current workaround I have, which is very much a hack is a @BoostrapConfiguration class that registers a BeanPostProcessor to wrap the ConsulPropertySourceLocator and clear() the context's before the next invocation of locate() is called.

@BootstrapConfiguration
public class FixConsulPropertySourceLocatorBootstrapConfiguration {
    @Bean
    public BeanPostProcessor fixConsulPropertySourceLocatorBeanPostProcessor() {
        return new BeanPostProcessor() {
            @Override
            public Object postProcessAfterInitialization(final Object bean, final String beanName) throws BeansException {
                if (bean instanceof ConsulPropertySourceLocator) {
                    return new FixedConsulPropertySourceLocator((ConsulPropertySourceLocator) bean);
                } else {
                    return bean;
                }
            }
        };
    }
    
    static class FixedConsulPropertySourceLocator implements PropertySourceLocator, ConsulConfigIndexes {
        private final ConsulPropertySourceLocator delegate;
        public FixedConsulPropertySourceLocator(final ConsulPropertySourceLocator delegate) {
            this.delegate = delegate;
        }

        @Override
        public PropertySource<?> locate(final Environment environment) {
            delegate.getContexts().clear();
            return delegate.locate(environment);
        }

        @Override
        public LinkedHashMap<String, Long> getIndexes() {
            return delegate.getIndexes();
        }
    }
}

It would be nice if this was fixed upstream and in a better manor than I have attempted here.

This then makes the ConsulPropertySource's for that Environment appear as expected:

0 = "config/service,A/"
1 = "config/service,B/"
2 = "config/service/"
3 = "config/application,A/"
4 = "config/application,B/"
5 = "config/application/"

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with ConsulPropertySourceLocator, especially locate(Environment), getContexts(), and the ConsulConfigIndexes state described in the report. Reproduce the supplied SpringApplicationBuilder context hierarchy with profiles A and B, then verify that the resulting ConsulPropertySource list contains each expected context once and that profile B overrides the default profile.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, spring, spring-boot
Domain
backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.