spring-cloud / spring-cloud/spring-cloud-consul
ServiceWatch for discovery is missing
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 822
- Forks
- 539
- Avg merge
- 9h 31m
- Merged PRs (30d)
- 7
Description
Hello
I found out, that in the consul-discovery-module is no watch-job like in the consul-config-module, which publishes a "RefreshEvent" when a service at consul is changed. I build it now on my own, but I think it would be helpful for other dev-guys when it is inside of the discovery-module.
This is my current way, I have implemented this watch. Perhaps it makes it faster to integrate.
Thank you.
/**
* This method uses the "consul.getAgentServices" to get the current list of services
* which are registered at consul.
*
* If some service is changed a "Refresh"-Event is published, that all "RefreshScoped"
* Beans will be build again. To set the delay between the sync set the
* spring.consul.discovery.watchDelay property. Default is 1000 milisecounds.
*/
@Scheduled(fixedDelayString = "${spring.consul.discovery.watchDelay:1000}")
public void watchServices() {
if (this.running.get()) {
try {
if (firstTime) {
log.info("Load baseline of consul services.");
Response<Map<String, Service>> response = consul.getAgentServices();
if (response.getValue() != null) {
response.getValue().keySet().forEach(key -> currentStoredServices
.put(key, response.getValue().get(key)));
}
firstTime = false;
}
else {
Response<Map<String, Service>> response = null;
response = this.consul.getAgentServices();
if (response.getValue() != null && !response.getValue().isEmpty()) {
Map<String, Service> remoteServices = response.getValue();
remoteServices.keySet().forEach(key -> {
if (!remoteServices.get(key).getId()
.startsWith(instanceId)
&& (!currentStoredServices.containsKey(key)
|| !remoteServices.get(key).toString()
.equals(currentStoredServices.get(key)
.toString()))) {
if (log.isDebugEnabled()) {
log.debug(
"Services changed, fire refresh event. New:{} Old: {}",
remoteServices.get(key).toString(),
currentStoredServices.get(key));
}
else {
log.info("Services changed, fire refresh event.");
}
RefreshEventData data = new RefreshEventData(key,
currentStoredServices.get(key),
remoteServices.get(key));
this.publisher.publishEvent(
new RefreshEvent(this, data, data.toString()));
this.currentStoredServices.put(key,
remoteServices.get(key));
}
});
}
}
}
catch (Exception e) {
// only fail fast on the initial query, otherwise just log the error
if (firstTime && this.properties.isFailFast()) {
log.error(
"Fail fast is set and there was an error reading services from consul.");
ReflectionUtils.rethrowRuntimeException(e);
}
else if (log.isDebugEnabled()) {
log.debug("Error querying services from consul. ", e);
}
else if (log.isWarnEnabled()) {
// simplified one line log message in the event of an agent
// failure
log.warn("Error querying services from consul. Message: "
+ e.getMessage());
}
}
}
}
@Data
static class RefreshEventData {
private final String context;
private final Service prevService;
private final Service newService;
}
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Compare the consul-discovery-module with the watch-job in the consul-config-module, starting with the existing getAgentServices and RefreshEvent usage shown in the issue. Add discovery service watching with the proposed delay and baseline behavior, then verify that service changes publish refresh events without disrupting startup error handling.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, spring, spring-boot
- Domain
- backend, cloud, distributed-systems
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100