use of org.apache.dubbo.remoting.etcd.ChildListener in project dubbo by alibaba.
the class EtcdRegistry method doSubscribe.
@Override
public void doSubscribe(URL url, NotifyListener listener) {
try {
if (ANY_VALUE.equals(url.getServiceInterface())) {
String root = toRootPath();
/*
* if we are interested in all interfaces,
* find out the current container or create one for the url, put or get only once.
*/
ConcurrentMap<NotifyListener, ChildListener> listeners = Optional.ofNullable(etcdListeners.get(url)).orElseGet(() -> {
ConcurrentMap<NotifyListener, ChildListener> container, prev;
prev = etcdListeners.putIfAbsent(url, container = new ConcurrentHashMap<>());
return prev != null ? prev : container;
});
/*
* if we have no interface watcher listener,
* find the current listener or create one for the current root, put or get only once.
*/
ChildListener interfaceListener = Optional.ofNullable(listeners.get(listener)).orElseGet(() -> {
ChildListener childListener, prev;
prev = listeners.putIfAbsent(listener, childListener = (parentPath, currentChildren) -> {
/*
* because etcd3 does not support direct children watch events,
* we should filter not interface events. if we watch /dubbo
* and /dubbo/interface, when we put a key-value pair {/dubbo/interface/hello hello},
* we will got events in watching path /dubbo.
*/
for (String child : currentChildren) {
child = URL.decode(child);
if (!anyServices.contains(child)) {
anyServices.add(child);
/*
* if new interface event arrived, we watch their direct children,
* eg: /dubbo/interface, /dubbo/interface and so on.
*/
subscribe(url.setPath(child).addParameters(INTERFACE_KEY, child, CHECK_KEY, String.valueOf(false)), listener);
}
}
});
return prev != null ? prev : childListener;
});
etcdClient.create(root);
/*
* at the first time, we want to pull already interface and then watch their direct children,
* eg: /dubbo/interface, /dubbo/interface and so on.
*/
List<String> services = etcdClient.addChildListener(root, interfaceListener);
for (String service : services) {
service = URL.decode(service);
anyServices.add(service);
subscribe(url.setPath(service).addParameters(INTERFACE_KEY, service, CHECK_KEY, String.valueOf(false)), listener);
}
} else {
List<URL> urls = new ArrayList<>();
for (String path : toCategoriesPath(url)) {
/*
* if we are interested in special categories (providers, consumers, routers and so on),
* we find out the current container or create one for the url, put or get only once.
*/
ConcurrentMap<NotifyListener, ChildListener> listeners = Optional.ofNullable(etcdListeners.get(url)).orElseGet(() -> {
ConcurrentMap<NotifyListener, ChildListener> container, prev;
prev = etcdListeners.putIfAbsent(url, container = new ConcurrentHashMap<>());
return prev != null ? prev : container;
});
/*
* if we have no category watcher listener,
* we find out the current listener or create one for the current category, put or get only once.
*/
ChildListener childListener = Optional.ofNullable(listeners.get(listener)).orElseGet(() -> {
ChildListener watchListener, prev;
prev = listeners.putIfAbsent(listener, watchListener = (parentPath, currentChildren) -> EtcdRegistry.this.notify(url, listener, toUrlsWithEmpty(url, parentPath, currentChildren)));
return prev != null ? prev : watchListener;
});
etcdClient.create(path);
/*
* at the first time, we want to pull already category and then watch their direct children,
* eg: /dubbo/interface/providers, /dubbo/interface/consumers and so on.
*/
List<String> children = etcdClient.addChildListener(path, childListener);
if (children != null) {
urls.addAll(toUrlsWithEmpty(url, path, children));
}
}
notify(url, listener, urls);
}
} catch (Throwable e) {
throw new RpcException("Failed to subscribe " + url + " to etcd " + getUrl() + ", cause: " + (OptionUtil.isProtocolError(e) ? "etcd3 registry may not be supported yet or etcd3 registry is not available." : e.getMessage()), e);
}
}
use of org.apache.dubbo.remoting.etcd.ChildListener in project dubbo by alibaba.
the class EtcdServiceDiscovery method registerServiceWatcher.
protected void registerServiceWatcher(String serviceName) {
String path = root + File.separator + serviceName;
/*
* if we have no category watcher listener,
* we find out the current listener or create one for the current category, put or get only once.
*/
ChildListener childListener = Optional.ofNullable(childListenerMap.get(serviceName)).orElseGet(() -> {
ChildListener watchListener, prev;
prev = childListenerMap.putIfAbsent(serviceName, watchListener = (parentPath, currentChildren) -> dispatchServiceInstancesChangedEvent(serviceName));
return prev != null ? prev : watchListener;
});
etcdClient.create(path);
etcdClient.addChildListener(path, childListener);
}
use of org.apache.dubbo.remoting.etcd.ChildListener in project dubbo by alibaba.
the class JEtcdClientTest method test_watch_on_recoverable_connection.
@Test
public void test_watch_on_recoverable_connection() throws InterruptedException {
String path = "/dubbo/com.alibaba.dubbo.demo.DemoService/connection";
String child = "/dubbo/com.alibaba.dubbo.demo.DemoService/connection/demoService1";
final CountDownLatch notNotified = new CountDownLatch(1);
final CountDownLatch notTwiceNotified = new CountDownLatch(2);
final Holder notified = new Holder();
ChildListener childListener = (parent, children) -> {
notTwiceNotified.countDown();
switch(notified.increaseAndGet()) {
case 1:
{
notNotified.countDown();
Assertions.assertEquals(1, children.size());
Assertions.assertEquals(child.substring(child.lastIndexOf("/") + 1), children.get(0));
break;
}
case 2:
{
Assertions.assertEquals(0, children.size());
Assertions.assertEquals(path, parent);
break;
}
default:
Assertions.fail("two many callback invoked.");
}
};
client.addChildListener(path, childListener);
client.createEphemeral(child);
// make sure first time callback successfully
Assertions.assertTrue(notNotified.await(15, TimeUnit.SECONDS));
// connection error causes client to release all resources including current watcher
JEtcdClient.EtcdWatcher watcher = client.getChildListener(path, childListener);
watcher.onError(Status.UNAVAILABLE.withDescription("temporary connection issue").asRuntimeException());
// trigger delete after unavailable
client.delete(child);
Assertions.assertTrue(notTwiceNotified.await(15, TimeUnit.SECONDS));
client.removeChildListener(path, childListener);
}
use of org.apache.dubbo.remoting.etcd.ChildListener in project dubbo by alibaba.
the class JEtcdClientTest method test_watch_when_create_path.
@Test
public void test_watch_when_create_path() throws InterruptedException {
String path = "/dubbo/com.alibaba.dubbo.demo.DemoService/providers";
String child = "/dubbo/com.alibaba.dubbo.demo.DemoService/providers/demoService1";
final CountDownLatch notNotified = new CountDownLatch(1);
ChildListener childListener = (parent, children) -> {
Assertions.assertEquals(1, children.size());
Assertions.assertEquals(child.substring(child.lastIndexOf("/") + 1), children.get(0));
notNotified.countDown();
};
client.addChildListener(path, childListener);
client.createEphemeral(child);
Assertions.assertTrue(notNotified.await(10, TimeUnit.SECONDS));
client.removeChildListener(path, childListener);
client.delete(child);
}
use of org.apache.dubbo.remoting.etcd.ChildListener in project dubbo by alibaba.
the class EtcdRegistry method doUnsubscribe.
@Override
public void doUnsubscribe(URL url, NotifyListener listener) {
ConcurrentMap<NotifyListener, ChildListener> listeners = etcdListeners.get(url);
if (listeners != null) {
ChildListener etcdListener = listeners.remove(listener);
if (etcdListener != null) {
if (ANY_VALUE.equals(url.getServiceInterface())) {
String root = toRootPath();
etcdClient.removeChildListener(root, etcdListener);
} else {
// maybe url has many subscribed paths
for (String path : toUnsubscribedPath(url)) {
etcdClient.removeChildListener(path, etcdListener);
}
}
}
if (listeners.isEmpty()) {
etcdListeners.remove(url);
}
}
}
Aggregations