consul-api icon indicating copy to clipboard operation
consul-api copied to clipboard

Add client support for Watches

Open ghost opened this issue 10 years ago • 7 comments

It would be great if real-time notification of config changes (KV data changes) were possible on the client-side.

I believe this concept is supported in the "raw" Consult API via watches, however I don't see that concept supported by this library.

The idea is simple:

  • Allow clients to register their own callbacks/watches with the Consul cluster
  • The callback/watch will now execute when the cluster senses a change to config data (or anything really)

The idea is to allow GOSSIP to "do its thing" and update clients in real-time, rather than forcing clients to poll.

ghost avatar Jun 18 '15 16:06 ghost

Hi

I also like use this feature but the implementation wouldn't be easy, Consul do not provide http api to register watches, currently I just adding watches by executing Consul agent commands from java Runtime.getRuntime().exec(...) so firslty we have to wait for exposing new http api methods in Consul :(

pszymczyk avatar Sep 10 '15 14:09 pszymczyk

Consul do not provide http api to register watches

Yes. This is the only thing that stops me from implementation

vgv avatar Sep 10 '15 14:09 vgv

Watches are implemented using blocking queries in the HTTP API. Agents automatically make the proper API calls to watch for changes and inform a handler when the data view has updated.

I believe we can find those HTTP commands using a simple sniffer proxy.

update: I created a simple http reverse proxy w/ logging using node.js, Check out this log :

Request /v1/kv/foo
{
  "host": "127.0.0.1:8501",
  "user-agent": "Go-http-client/1.1",
  "accept-encoding": "gzip"
}
Response {
  "content-type": "application/json",
  "x-consul-index": "48",
  "x-consul-knownleader": "true",
  "x-consul-lastcontact": "0",
  "date": "Sat, 15 Oct 2016 10:16:56 GMT",
  "content-length": "88",
  "connection": "close"
}

Request /v1/kv/foo?index=48
{
  "host": "127.0.0.1:8501",
  "user-agent": "Go-http-client/1.1",
  "accept-encoding": "gzip"
}
Response {
  "content-type": "application/json",
  "x-consul-index": "221",
  "x-consul-knownleader": "true",
  "x-consul-lastcontact": "0",
  "date": "Sat, 15 Oct 2016 10:17:13 GMT",
  "content-length": "89",
  "connection": "close"
}

Request /v1/kv/foo?index=221
{
  "host": "127.0.0.1:8501",
  "user-agent": "Go-http-client/1.1",
  "accept-encoding": "gzip"
}

It seems that at first, the client looks for the current value of the key, after that, it queries the same key w/ a query string parameter named "index" that returned from the last result, at this point, the HTTP request is blocking until the key is updated...

update 2: Same thing happens for keyprefix:

Request /v1/kv//?recurse=
{
  "host": "127.0.0.1:8501",
  "user-agent": "Go-http-client/1.1",
  "accept-encoding": "gzip"
}
Response {
  "content-type": "application/json",
  "x-consul-index": "221",
  "x-consul-knownleader": "true",
  "x-consul-lastcontact": "0",
  "date": "Sat, 15 Oct 2016 10:20:22 GMT",
  "content-length": "89",
  "connection": "close"
}

Request /v1/kv//?index=221&recurse=
{
  "host": "127.0.0.1:8501",
  "user-agent": "Go-http-client/1.1",
  "accept-encoding": "gzip"
}

(BTW, the request and responses that you see are the headers and not the body)

shanielh avatar Oct 15 '16 09:10 shanielh

It's pretty easy to implement on this client, I managed to do so without any need to modify the client.

Good job @vgv and ecwid :+1:

shanielh avatar Oct 15 '16 16:10 shanielh

below are sample code based on @shanielh explanation:

        private static void longPolling(String serviceName){
				
		long consulIndex = -1;
		do{
			
			QueryParams param = 
					QueryParams.Builder.builder()
					.setIndex(consulIndex)
					.build();
			
			Response<List<HealthService>> healthyServices = 
					consulClient.getHealthServices(serviceName, true, param);
					
			consulIndex = healthyServices.getConsulIndex();
			
			List<HealthService> services = healthyServices.getValue();
			for (HealthService healthyService : services) {
				logger.info("Updated services info: {}", healthyService);
			}
			
			
		}while(true);		
		
	}

thiamteck avatar Oct 24 '17 03:10 thiamteck

can support watch service now? rickfast's consul-client hava a class ServiceHealthCache support watch service.

ctlove0523 avatar Mar 24 '21 07:03 ctlove0523

Hi, I also started looking at this implementation and looking for watch service. Would it be implemented?

walkerfunction avatar Oct 26 '21 21:10 walkerfunction