ServiceWatch for discovery is missing
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;
}
I think that is what ConsulCatalogWatch does, is it not?
I thought so, but the ConsulCatalogWatch publishes a HeartbeatEvent not a RefreshEvent and the CatalogService-Response just contains service-names and tags, no address, port etc.
also confused about this, i can not find any class to handle this event and refresh service info from consul, can someone tell me ? waiting for feedack
I'd be willing to do something if there is a blocking request like implemented by ConsulCatalogWatch. I'd rather not poll.
I have a same requirement where I want to know if a new service has joined the cluster or any old service is now back online i.e. in short watch on registered service on consul. What is the preferred way of doing this?