Programming Zookeeper – Watcher

The common pattern of Zookeeper is 1) to check existence of a znode or 2) to read a znode data.

Let’s suppose that you are building a program which does some action whenever a znode data is changed. The way to implement it is 1) to read the znode data periodically or 2) to get notified when the data is changed.

Notification is a much more efficient way. And Watcher is the way to do it.

Watcher can be registered for events, such as znode data change, znode creation, znode delete, child node change.

There are some points to consider when using Watcher.

  • Watcher is an one time trigger. Therefore, to get notified continually, you must register it again after get notified (same limitation in Curator)
  • The event between Watcher callback and re-registeration is lost. Therefore, you should check/read the znode again when Watcher callback is invoked
  • Watcher registeration is lost when connection is lost or resumed again

The following is a sample which checks a znodes’ data continally.

import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.EventType;

public class ZookeeperWatcherTest{
	private ZooKeeper zooKeeper;
	private String testNode = "/testNode";
	private DataAdapter dataAdapter;
	private DataWatcher dataWatcher;

	public ZookeeperWatcherTest(ZooKeeper zooKeeper) {
		this.dataWatcher = new DataWatcher();
		this.dataAdapter = new DataAdapter();
		this.zooKeeper = zooKeeper;
	}

	public void registerDataWatcher() throws Exception{
		Stat stat = this.zooKeeper.exists(this.testNode, false);
		this.zooKeeper.getData(this.testNode, this.dataWatcher, stat);
	}

	private class DataWatcher implements Watcher{
		@Override
		public void process(WatchedEvent event) {
			try {
				if(event.getType() == EventType.NodeDataChanged && event.getPath().equals(testNode)) {
					dataAdapter.readTestNode();
				}
			}
			catch(Exception e) {
				e.printStackTrace();
			}
		}
	}

	private class DataAdapter{
		private void readTestNode() throws Exception{
			Stat stat = zooKeeper.exists(testNode, false);
			byte [] nodeData = zooKeeper.getData(testNode, dataWatcher, stat); // Register watcher again
			// Process nodeData
		}
	}

}
  • At registerDataWatcher(), Watcher is registered (by getData()’s argument)
  • DataAdapter.readTestNode() is called when Watcher event occurs
  • When it reads data, it passes Watcher instance to register it again

 

 

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.