Home > Software engineering >  Azure Spring Cloud AppConfiguration refresh is not working
Azure Spring Cloud AppConfiguration refresh is not working

Time:12-01

im having some problems refreshing anything, be it @ConfigurationProperties or @Value, using the

implementation("com.azure.spring:azure-spring-cloud-appconfiguration-config:2.1.1")

library. From what i could find and debug, the inner AppConfigurationRefresh class is called and the RefreshEvent is created reacting correctly to changes done in Azure Config Server. Problem is that, when context is updated, there also should be new values recognized by the ContextRefresher, which is not the case for me.

Spring Boot ContextRefresher

    public synchronized Set<String> refreshEnvironment() {
        Map<String, Object> before = extract(this.context.getEnvironment().getPropertySources());
        updateEnvironment();
        Set<String> keys = changes(before, extract(this.context.getEnvironment().getPropertySources())).keySet();
        this.context.publishEvent(new EnvironmentChangeEvent(this.context, keys));
        return keys;
    }

The result of that refresh method is always empty, which means no changes were found.

Logs generated by the refresh event:

2021-11-29 19:53:03.543  INFO [] 34820 --- [         task-2] c.a.s.c.config.AppConfigurationRefresh   : Configuration Refresh Event triggered by /myprefix/my.config.value
2021-11-29 19:53:53.694  INFO [] 34820 --- [         task-2] b.c.PropertySourceBootstrapConfiguration : Located property source: [BootstrapPropertySource {name='bootstrapProperties-/application/https://my-config-store-stage.azconfig.io/dev'}]
2021-11-29 19:53:53.719  INFO [] 34820 --- [         task-2] o.s.boot.SpringApplication               : The following profiles are active: messaging,db,dev
2021-11-29 19:53:53.736  INFO [] 34820 --- [         task-2] o.s.boot.SpringApplication               : Started application in 3.347 seconds (JVM running for 158.594)
2021-11-29 19:54:01.265  INFO [] 34820 --- [         task-2] o.s.c.e.event.RefreshEventListener       : Refresh keys changed: []
2021-11-29 19:54:03.553  INFO [] 34820 --- [   scheduling-1] d.l.d.a.s.c.AppConfigurationUpdater      : All configurations were refreshed.

bootstrap.yml

spring:
      cloud:
        azure:
          appconfiguration:
            stores:
              - connection-string: ${connection-string}
                selects:
                  - key-filter: '/myprefix/'
                    label-filter: dev
    
                monitoring:
                  enabled: true
                  refresh-interval: 1s
                  triggers:
                    -
                      label: dev
                      key: /myprefix/my.config.value

I only noticed one thing that could be relevant to this, looking at log from start of the application (where everything is loaded properly) and at the point of refresh:

2021-11-29 19:51:31.578  INFO [] 34820 --- [           main] b.c.PropertySourceBootstrapConfiguration : Located property source: [BootstrapPropertySource {name='bootstrapProperties-/myprefix/https://my-config-store-stage.azconfig.io/dev'}, BootstrapPropertySource {name='bootstrapProperties-/application/https://my-config-store-stage.azconfig.io/dev'}]

2021-11-29 19:53:53.694  INFO [] 34820 --- [         task-2] b.c.PropertySourceBootstrapConfiguration : Located property source: [BootstrapPropertySource {name='bootstrapProperties-/application/https://my-config-store-stage.azconfig.io/dev'}]

It seems that when refreshing, the Spring is not able to locate all BootstrapPropertySources and maybe thats why there are no changes found. Am i missing some configuration somewhere to specify these or does anyone know whats the problem here. Thanks

CodePudding user response:

You should be using "com.azure.spring:azure-spring-cloud-appconfiguration-config-web:2.1.1" if you want to enable auto refresh. Otherwise you have to manually trigger refresh using AzureCloudConfigRefresh's refreshConfiguration. See: https://github.com/Azure/azure-sdk-for-java/tree/main/sdk/appconfiguration/azure-spring-cloud-starter-appconfiguration-config#configuration-refresh

As for the ContextRefresher, is it inside of the refresh scope? If not then the values are unable to be changed.

Though looking at your logs you don't seem to be picking up the changes. Can you take a look at this demo?

https://github.com/Azure-Samples/azure-spring-boot-samples/tree/main/appconfiguration/azure-appconfiguration-refresh-sample

The instructions to run it are here https://github.com/Azure-Samples/azure-spring-boot-samples/pull/106/files

CodePudding user response:

The Problem

The changed values in azure appconfig store are triggering refresh event (either automaticaly using "web" version of library or through manual call to AppConfigurationRefresh.refreshConfigurations) and you can see it in the logs like this:

2021-11-29 19:53:03.543  INFO [] 34820 --- [         task-2] c.a.s.c.config.AppConfigurationRefresh   : Configuration Refresh Event triggered by /myprefix/my.config.value
2021-11-29 19:53:53.694  INFO [] 34820 --- [         task-2] b.c.PropertySourceBootstrapConfiguration : Located property source: [BootstrapPropertySource {name='bootstrapProperties-/application/https://my-config-store-stage.azconfig.io/dev'}]
2021-11-29 19:53:53.719  INFO [] 34820 --- [         task-2] o.s.boot.SpringApplication               : The following profiles are active: messaging,db,dev
2021-11-29 19:53:53.736  INFO [] 34820 --- [         task-2] o.s.boot.SpringApplication               : Started application in 3.347 seconds (JVM running for 158.594)
2021-11-29 19:54:01.265  INFO [] 34820 --- [         task-2] o.s.c.e.event.RefreshEventListener       : Refresh keys changed: []

However the Spring Boot is unable to locate any changes in PropertySources as is evident from:

2021-11-29 19:54:01.265  INFO [] 34820 --- [         task-2] o.s.c.e.event.RefreshEventListener       : Refresh keys changed: []

The Research

What actually was deciding factor for me to find the issue, was indeed the difference between the found BootstrapPropertySources at the start of the application and at the refresh.

2021-11-29 19:51:31.578  INFO [] 34820 --- [           main] b.c.PropertySourceBootstrapConfiguration : Located property source: [BootstrapPropertySource {name='bootstrapProperties-/myprefix/https://my-config-store-stage.azconfig.io/dev'}, BootstrapPropertySource {name='bootstrapProperties-/application/https://my-config-store-stage.azconfig.io/dev'}]

2021-11-29 19:53:53.694  INFO [] 34820 --- [         task-2] b.c.PropertySourceBootstrapConfiguration : Located property source: [BootstrapPropertySource {name='bootstrapProperties-/application/https://my-config-store-stage.azconfig.io/dev'}]

The culprit for the not found changes is indeed the missing BootstrapPropertySource at the update. From my testing its evident, that all configuration properties are dependant on the name of the PropertySource they came from and if its missing, they will retain their original old value.

The problem is in the way the appconfig library is locating/creating the BootstrapPropertySources and does not differentiate between startup and update.

The following code is from appconfiguration library and i only took the part that is causing the bug.

public final class AppConfigurationPropertySourceLocator implements PropertySourceLocator {
...
@Override
public PropertySource<?> locate(Environment environment) {
...
    String applicationName = this.properties.getName();
    if (!StringUtils.hasText(applicationName)) {
        applicationName = env.getProperty(SPRING_APP_NAME_PROP);
    }
...
}
...
}

The problem here is that env.getProperty(SPRING_APP_NAME_PROP); is filled with "spring.application.name" during startup, because spring loads all .yml files at once, but is not available during update. Also the AppConfigurationProperties properties.name is never mentioned in any documentation from azure, but is crutial to overcome this problem.

The Solution

If you are using custom spring.application.name include some name also into the bootstrap.yml like this:

spring:
  cloud:
    azure:
      appconfiguration:
        name: your-name #any value will work
        stores:
          - connection-string: ${connection-string}
            selects:
              - key-filter: '/myprefix/'
                label-filter: dev

            monitoring:
              enabled: true
              refresh-interval: 1s
              triggers:
                -
                  label: dev
                  key: /myprefix/my.config.value

This will make the library use the properties name value at all times and avoid usage of the problematic spring.application.name value.

  • Related