-
Notifications
You must be signed in to change notification settings - Fork 163
Watcher
One feature of ZooKeeper that is really neat is the concept of Watchers. Essentially, whenever an operation occurs on a znode, anyone registered as a watcher of that znode is notified over the existing channel of that operation.
One of the primary goals for Noah is to implement this same concept with a few differences. In ZooKeeper, watches are ephemeral. Once a watch event has fired, the client must re-register for any new watches. In Noah, watches are planned to be persistent. The watcher framework is planned to work like so:
- Via the callback support in
Ohm-contrib
actions on models fire off an Redis publish message - The watcher daemon (NYI) subscribes to all messages (or a subset - documented below) and performs performs operations based on any registered watchers.
Currently, all the base publish messages are being performed for create, update, save and delete. These are fired AFTER the operation is completed. Messages are publish to the Redis queue via patterns like so:
Warning! The patterns described below are invalid. The format has changed. This will be updated
noah.<Model>[<instance name>].<action>
For instance, if a new Application called myrailsapp1
is created, a message will be published to Redis under the following pattern:
noah.Application[myrailsapp1].create
The body of the message is essentially the same as that provided by the REST API which simply calls the object's to_json
method which is created automatically via the Ohm to_hash
override.
Using the Redis psubscribe
method, you can watch everything that comes across for a given action, object type or specific object:
redis> PSUBSCRIBE noah.*.create
Reading messages... (press Ctrl-c to quit)
1. "psubscribe"
2. "noah.*.create"
3. (integer) 1
1. "pmessage"
2. "noah.*.create"
3. "noah.Configuration[mystringconf].create"
4. "{\"id\":\"1\",\"name\":\"mystringconf\",\"format\":\"string\",\"body\":\"some_var\",\"created_at\":\"2011-02-14 06:55:10 UTC\",\"updated_at\":\"2011-02-14 06:55:10 UTC\",\"application\":null}"
1. "pmessage"
2. "noah.*.create"
3. "noah.Configuration[mystringconf].create"
4. "{\"id\":\"1\",\"name\":\"mystringconf\",\"format\":\"string\",\"body\":\"some_var\",\"created_at\":\"2011-02-14 06:55:10 UTC\",\"updated_at\":\"2011-02-14 06:55:10 UTC\",\"application\":null}"
You can also watch via Ruby:
require 'redis'
require 'json'
redis = Redis.connect
redis.psubscribe("noah.*.create") do |on|
on.psubscribe do |channel, subscriptions|
puts "Subscribed to ##{channel} (#{subscriptions} subscriptions)"
end
on.pmessage do |pattern, channel, message|
puts channel +" - "+ message
end
end
There's a small difference in the message for deletions. When a delete method is called in Ohm, the only thing that remains after the fact of the original object is its id
. Because of that, special precautions had already been made in the REST API to preserve some object attributes before deletion to provide a robust reponse. Something similar is being done for published messages.
Before an object is deleted, the name
attribute of the object is persisted in an instance variable called deleted_name
. After delete is called, the message pushed to subscribers contains the basic hash with the id and name (via @deleted_name) in the message. The remainder of the attributes are null. Note that the object does not exist by that name and any attempt to reference by that name will fail. This information is only for reference.
A few pattern examples
- Watching a specific
Host
:
PSUBSCRIBE noah.Host[somehost].*
- Watching all hosts:
PSUBSCRIBE noah.Host*
- Watching all Service creations:
PSUBSCRIBE noah.Service[*].create
- Watching all Configuration updates:
PSUBSCRIBE noah.Configuration[*].update
- Watching all deletes:
PSUBSCRIBE noah.*.delete