15 August
2007
Digg digg it  |  Slashdot slashdot.org  |  Reddit reddit  |  del.icio.us del.icio.us  |  Technorati Technorati

Event Horizon: Devil Framework's event management system

A story about events, filters, situations and some other details where the Devil (Framework) lives.

Bolz and me recently had a deep-though brainstorming day analyzing and reevaluating the event processing engine embedded into the Devil Framework's Application Server. We had just taken a deep look in some Complex Event Processing systems (especially Colar8) so we wanted to verify that our system was in good shape among its buddies.

Architecture

The Application Server is designed around "events". Its conceptual design is really very simple:

As you can see this is just a simple input-process-output chain. The real power lies in the modular architecture that allows adding and removing plugins as needed, without downtime, and by the policy-based dynamic configuration system that can change system's modus operandi at specified times or when some kind of event occurs.

Plugins

Now I'm going to briefly describe three event-related plugins provided with the Devil Framework: the Filters Manager, the Situations Manager and the Events Manager.

Filters Manager

The Filters Manager is really two mangle plugins in one as it installs itself as the first and the last plugin to receive events form the mangle queue. This plugin implements and manages a distributed, hierarchical event filtering system.

A filter is a processing entity that takes events as input and evaluates a Python expression (that must return True or False) against each one of them. Different Python code is than executed based on the filter's return value and the events are (not) passed to subsequent filters.

Filters can be defined on each node or in a global repository and referenced by a node filter (filters can be nested into other filters). By default no filter is active and so no event is passed to any filter. To activate a filter you must add to the Pre or/and Post Autostart Filters' list.

A filter definition includes:

Situations Manager

Situations are a kind of filters, but with memory and continuous evaluation (filters are only evaluated when an event is received). Management is very similar to the filters' one: there are global and local repositories of situations, facts, macros and autostart list (to specify which situations must be made active at startup).

Facts? What's a fact?

Facts are a situation's building blocks. A fact is something like "the light number 5 is turned on" or "there's somebody in the room 1" and when you question it it return its status (True or False). You can configure a fact to refresh itself (reevaluating the eval code without any incoming event) every X seconds, to limit the number of status changes, to be activated by only some kind of events or by events satisfying some condition (es. "event.timestamp < last_event_timestamp + 10" to accept an event only if it occurs less than 10 seconds after the last accepted event).

Situations can be defined by any number of facts and can have any number of child situations (that can be activated on status changes). Situation can be in one of two states ("entered" or "exited") depending on the return value of the "eval (timestamp)" callback. An example may be if "light_1_on_fact and not somebody_in_room_1_fact" then "close_light (1)" and emit event "light_closed" with attribute "number" set to 1. You can also limit the number of times a situation can be reused before being destroyed.

To explain the concepts better here it's how the situation's engine works:

Once you grab how this sub-system works you can implement really complex event processing solutions with relative easy. And remember that from all the various callbacks you can access the full API of the system.

Events Manager

Well, the Events Manager has a misleading name, as the events it refers to are not the events I've talked about till now. This plugin augments the framework with a GUI like event subscription system, something like Trolltech Qt's slots and signals. Slots are just names to which signal handler are binded to. This signal handlers are invoked when a signal with the right name is emitted.

I want to talk about this plugin because it's an example of how you can use events: "GUI events" are propagated to other nodes and connected consoles encapsulating them into regular events.

The API is very simple:

When an handler is invoked it receives as its first argument the event. An event is a Python dictionary defined as follows:

event = {
        'slot': slot, # slot name
        'routing': routing, # routing policy (None, 'local', ['local', ...])
        'kargs': kargs, # optional arguments
        'user_uid': user_uid, # user id of the event emitter
        'user_info': user_info, # user_info structure of the event emitter
        'drop': False, # drop event flag, set it to True to drop event and prevent calling other handler
        'multicast': False, # multicasting flag
        'blocking': False, # True to block till all handlers are executed
}

A cool feature is that an IceBridge console can bind local handlers to slots on the Application Server it is connected to:

api.events_manager.bind ('rpc:remote_slot', uid, handler)

However you can not "transparently" emit node's events from the console (but you can always use the Events Manager node's API).

The Visualization Side of Life

OK, but when all those events reach an IceBridge console, what can we do with them?

First of all there's a way to intercept and filter incoming events before any console sub-system can take a look at them, using the "api.events_server.add_filter (uid, name, filter)" API. We use this API to process incoming "GUI events" and system wide users' messages. If a filter function returns True, the event is removed from the processing queue.

Another way to get events is using the "api.events_server.add_observer (uid, name, callback, pre_filters=False)" API. The difference between observers and filters is that observers can not dump events from the processing queue.

Views

Then the events will encounter some (opened) view. Views are GUI interfaces developed using the Views Editor and that can be displayed using the Views Browser or embedded in any custom window or dialog (to be more precise, the Views Editor is just an operational mode of the Views Browser; you can start editing a view also while you are using it).

In a view you can insert and edit a whole set of standard (and not so standard) widgets like you do in your preferred GUI editor (an the Views Editor is heavily inspired by Qt Designer), with the difference that you can also add/edit Python code to them and test the view "live", just switching to "view" mode (you can see that the view is always live, even in edit mode, looking at the bottom/right corner of the picture above, where an embedded panel displays the CPU status of an Application Server).

All views and their widgets can receive incoming events but by default they do not react to them. You must set the desired target's (view or widget) "update_mode" property to "wait": this tells the target that it will wait for events (all kinds by default, but you can also select which kind of events you are interested into) and that every X seconds, if any event was received, it must emit the "events" signal. Then you just need to write some code into the "on_events (events)" target's signal handler. That's it!

Final Words Of Self Overindulgence

Mmmmmm..... well...... at the end I think our little Complex Event Processing system can stand quite proud between its pals. Sure, it has its weaknesses (compared to the C based engines it's relatively slow) but it has also its strengths (very, very flexible and customizable, and once you know Python, you are ready to go).

Pat-pat..... ;-)


Category Devil Framework 
Posted by alex at 18:19 | Comments (0) | Trackbacks (0)
<< On how I've just killed a Python thread... | Main | A small (but complete) Python ctypes-based Net-SNMP wrapper module. >>
Comments
There is no comment.
Trackbacks
Please send trackback to:http://www.dlevel.com/blogs/alex/21/tbping
There is no trackback.