Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import java.util.List;

import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
Expand All @@ -30,6 +31,7 @@
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.cloud.bus.BusProperties;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.config.server.environment.JGitEnvironmentRepository;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
Expand Down Expand Up @@ -115,11 +117,12 @@ protected static class PropertyPathEndpointConfiguration {

@Bean
public PropertyPathEndpoint propertyPathEndpoint(List<PropertyPathNotifier> notifiers,
MonitorConfigurationProperties monitorProperties) {
MonitorConfigurationProperties monitorProperties,
ObjectProvider<JGitEnvironmentRepository> gitRepositories) {
Assert.state(!notifiers.isEmpty(), "At least one PropertyPathNotifier must be available");
return new PropertyPathEndpoint(new CompositePropertyPathNotificationExtractor(this.extractors), notifiers,
monitorProperties.getMaxDashes(), monitorProperties.getMaxPaths(),
monitorProperties.getIgnoredPaths());
monitorProperties.getIgnoredPaths(), gitRepositories.orderedStream().toList());
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.cloud.config.server.environment.JGitEnvironmentRepository;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.util.StringUtils;
Expand Down Expand Up @@ -71,6 +72,13 @@ public class PropertyPathEndpoint {

private final List<Pattern> ignoredPaths;

/**
* Git repositories of this config server. Their refresh rate is expired before the
* applications are notified, so that the configuration the applications fetch on
* refresh includes the change that triggered the notification.
*/
private final List<JGitEnvironmentRepository> gitRepositories;

public PropertyPathEndpoint(PropertyPathNotificationExtractor extractor, PropertyPathNotifier notifier) {
this(extractor, List.of(notifier), MonitorConfigurationProperties.DEFAULT_MAX_DASHES);
}
Expand All @@ -88,7 +96,13 @@ public PropertyPathEndpoint(PropertyPathNotificationExtractor extractor, List<Pr

public PropertyPathEndpoint(PropertyPathNotificationExtractor extractor, List<PropertyPathNotifier> notifiers,
int maxDashes, int maxPaths, List<String> ignoredPaths) {
this(extractor, notifiers, maxDashes, maxPaths, ignoredPaths, Collections.emptyList());
}

public PropertyPathEndpoint(PropertyPathNotificationExtractor extractor, List<PropertyPathNotifier> notifiers,
int maxDashes, int maxPaths, List<String> ignoredPaths, List<JGitEnvironmentRepository> gitRepositories) {
this.extractor = extractor;
this.gitRepositories = gitRepositories == null ? Collections.emptyList() : gitRepositories;
this.notifiers = notifiers;
this.maxDashes = maxDashes;
this.maxPaths = maxPaths;
Expand Down Expand Up @@ -121,6 +135,9 @@ public Set<String> notifyByPath(@RequestHeader HttpHeaders headers, @RequestBody
for (String service : services) {
log.info("Refresh for: " + service);
}
for (JGitEnvironmentRepository repository : this.gitRepositories) {
repository.expireRefreshRate();
}
for (PropertyPathNotifier notifier : this.notifiers) {
notifier.notifyApplications(services);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,12 @@
import java.util.List;
import java.util.Set;

import io.micrometer.observation.ObservationRegistry;
import org.junit.jupiter.api.Test;

import org.springframework.cloud.config.server.environment.JGitEnvironmentProperties;
import org.springframework.cloud.config.server.environment.JGitEnvironmentRepository;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.http.HttpHeaders;

import static org.assertj.core.api.Assertions.assertThat;
Expand Down Expand Up @@ -63,6 +67,37 @@ public void testNotifiesAffectedServices() {
assertThat(notifiedServices).containsExactly("foo");
}

@Test
public void testExpiresGitRefreshRateBeforeNotifyingServices() {
JGitEnvironmentRepository repository = gitRepository();
repository.setLastRefresh(System.currentTimeMillis());
List<Long> lastRefreshWhenNotified = new ArrayList<>();
PropertyPathNotifier notifier = services -> lastRefreshWhenNotified.add(repository.getLastRefresh());
PropertyPathEndpoint endpoint = new PropertyPathEndpoint(
new CompositePropertyPathNotificationExtractor(Collections.emptyList()), List.of(notifier),
MonitorConfigurationProperties.DEFAULT_MAX_DASHES, MonitorConfigurationProperties.DEFAULT_MAX_PATHS,
Collections.emptyList(), List.of(repository));

endpoint.notifyByPath(new HttpHeaders(), Collections.singletonMap("path", "foo.yml"));

assertThat(lastRefreshWhenNotified).containsExactly(0L);
}

@Test
public void testDoesNotExpireGitRefreshRateWhenNoServiceIsAffected() {
JGitEnvironmentRepository repository = gitRepository();
long lastRefresh = System.currentTimeMillis();
repository.setLastRefresh(lastRefresh);
PropertyPathEndpoint endpoint = new PropertyPathEndpoint(
new CompositePropertyPathNotificationExtractor(Collections.emptyList()), List.of(services -> {
}), MonitorConfigurationProperties.DEFAULT_MAX_DASHES, MonitorConfigurationProperties.DEFAULT_MAX_PATHS,
List.of("foo\\.yml"), List.of(repository));

endpoint.notifyByPath(new HttpHeaders(), Collections.singletonMap("path", "foo.yml"));

assertThat(repository.getLastRefresh()).isEqualTo(lastRefresh);
}

@Test
public void testNotifyAll() {
assertThat(this.endpoint.notifyByPath(new HttpHeaders(), Collections.singletonMap("path", "application.yml"))
Expand Down Expand Up @@ -145,4 +180,10 @@ public void testNotifyLimitsPaths() {
assertThat(limitedEndpoint.notifyByForm(new HttpHeaders(), request).toString()).isEqualTo("[foo, bar]");
}

private static JGitEnvironmentRepository gitRepository() {
JGitEnvironmentProperties properties = new JGitEnvironmentProperties();
properties.setRefreshRate(60);
return new JGitEnvironmentRepository(new StandardEnvironment(), properties, ObservationRegistry.NOOP);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -907,6 +907,15 @@ public void setLastRefresh(long lastRefresh) {
this.lastRefresh = lastRefresh;
}

/**
* Makes the next request fetch from the remote repository, even if the
* {@link #getRefreshRate() refresh rate} has not elapsed since the last fetch. Has no
* effect if the refresh rate is negative, in which case the remote is never fetched.
*/
public void expireRefreshRate() {
this.lastRefresh = 0;
}

/**
* Wraps the static method calls to {@link org.eclipse.jgit.api.Git} and
* {@link org.eclipse.jgit.api.CloneCommand} allowing for easier unit testing.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,13 @@ public void setRepos(Map<String, PatternMatchingJGitEnvironmentRepository> repos
this.repos.putAll(repos);
}

@Override
public void expireRefreshRate() {
super.expireRefreshRate();
this.repos.values().forEach(JGitEnvironmentRepository::expireRefreshRate);
new ArrayList<>(this.placeholders.values()).forEach(JGitEnvironmentRepository::expireRefreshRate);
}

@Override
public Locations getLocations(String application, String profile, String label) {
for (PatternMatchingJGitEnvironmentRepository repository : this.repos.values()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,37 @@ public void testNewCommitID() throws Exception {
assertThat("bar").isEqualTo(fooProperty);
}

@Test
public void expireRefreshRateFetchesNewCommitWithinRefreshRate() throws Exception {
JGitConfigServerTestData testData = JGitConfigServerTestData
.prepareClonedGitRepository(TestConfiguration.class);
JGitEnvironmentRepository repository = testData.getRepository();
repository.setRefreshRate(60);

// the first request fetches and starts the refresh rate window
Environment environment = repository.findOne("bar", "staging", "master");
String startingRemoteVersion = getCommitID(testData.getServerGit().getGit(), "master");
assertThat(environment.getVersion()).isEqualTo(startingRemoteVersion);

// update the remote repo
FileOutputStream out = new FileOutputStream(
new File(testData.getServerGit().getGitWorkingDirectory(), "bar.properties"));
StreamUtils.copy("foo: barNewCommit", Charset.defaultCharset(), out);
testData.getServerGit().getGit().add().addFilepattern("bar.properties").call();
testData.getServerGit().getGit().commit().setMessage("Updated for pull").call();
String updatedRemoteVersion = getCommitID(testData.getServerGit().getGit(), "master");

// within the refresh rate window the new commit is not fetched
environment = repository.findOne("bar", "staging", "master");
assertThat(environment.getVersion()).isEqualTo(startingRemoteVersion);

repository.expireRefreshRate();

environment = repository.findOne("bar", "staging", "master");
assertThat(environment.getVersion()).isEqualTo(updatedRemoteVersion);
assertThat(ConfigServerTestUtils.getProperty(environment, "bar.properties", "foo")).isEqualTo("barNewCommit");
}

@Test
/**
* In this scenario there is set the refresh rate so the remote repository is not
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,19 @@ private PatternMatchingJGitEnvironmentRepository createRepository(String name, S
return repo;
}

@Test
public void expireRefreshRateExpiresAllRepositories() {
long now = System.currentTimeMillis();
this.repository.setLastRefresh(now);
this.repository.getRepos().values().forEach(repo -> repo.setLastRefresh(now));

this.repository.expireRefreshRate();

assertThat(this.repository.getLastRefresh()).isZero();
assertThat(this.repository.getRepos()).isNotEmpty();
assertThat(this.repository.getRepos().values()).allSatisfy(repo -> assertThat(repo.getLastRefresh()).isZero());
}

@Test
public void defaultRepo() {
Environment environment = this.repository.findOne("bar", "staging", "master");
Expand Down