spring-cloud-consul icon indicating copy to clipboard operation
spring-cloud-consul copied to clipboard

ServiceWatch for discovery is missing

Open gataka opened this issue 8 years ago • 5 comments

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;

    }

gataka avatar Jul 24 '17 06:07 gataka

I think that is what ConsulCatalogWatch does, is it not?

spencergibb avatar Jul 24 '17 23:07 spencergibb

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.

gataka avatar Jul 25 '17 05:07 gataka

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

darren-fu avatar Jul 30 '17 02:07 darren-fu

I'd be willing to do something if there is a blocking request like implemented by ConsulCatalogWatch. I'd rather not poll.

spencergibb avatar Aug 04 '17 20:08 spencergibb

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?

mozinrat avatar Sep 12 '17 02:09 mozinrat