Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add client support for Watches #19

Open
ghost opened this issue Jun 18, 2015 · 7 comments
Open

Add client support for Watches #19

ghost opened this issue Jun 18, 2015 · 7 comments

Comments

@ghost
Copy link

ghost commented Jun 18, 2015

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.

@pszymczyk
Copy link

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 :(

@vgv
Copy link
Member

vgv commented Sep 10, 2015

Consul do not provide http api to register watches

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

@shanielh
Copy link

shanielh commented Oct 15, 2016

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
Copy link

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 👍

@thiamteck
Copy link

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);		
		
	}

@ctlove0523
Copy link

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

@walkerfunction
Copy link

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants