Skip to content
This repository has been archived by the owner on Dec 27, 2022. It is now read-only.

Watcher

John E. Vincent edited this page Mar 19, 2011 · 3 revisions

Watches and ZooKeeper

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.

Watches and Noah

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.

Messages

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.

via Redis CLI

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}"

via Ruby

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

Deleted items

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 delete

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.

Other examples

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