Simplify event system
Status: IsProposal
Author
Problem
Zope 3's event system is rather complicated:
- All event objects are required to implement IEvent? (or an interface that extends IEvent?)
- All subscribers are required to implement ISubscriber?. This makes it impossible to use functions as subscribers directly.
- We have local and global event-publication and event-subscription services. The event-subscription services provide some functionality that we don't use (filtering) and don't provide some functionality that we need (dispatching on both an event and the object the event is about).
- Dealing with path-based subscriptions adds complexity to the local-subscription service. Now that context wrappers have been removed, the service could be greatly simplified, if we needed to simplify it. It's not clear that we do.
Among other things, the complexity makes it hard to use the event system outside of Zope. It's just too heavy.
Recently, we've started using adapters to model event subscribers:
http://dev.zope.org/Wikis/Zope3/InstanceAndTypeBasedSubscriptions
This has worked very well. To support this, we've added a new kind of adapter - a subscription adapter. Subscription adapters work a bit like regular adapters except that they are cumulative. When we look up a subscription adapter, we don't get the best adapter that matches the objects we want to adapt, we get all of the adapters that match the objects.
It's worth noting that the subscription model supported by the existing event subscription services is actually a subscription-adapter model. We look up all of the adapters "for" a given event, based on the event type.
Proposal
I propose to greatly simplify the event architecture:
- Allow any object to be an event.
- Replace the existing global and local event publication and
subscription services with a simple event notification module.
This module will implement the following interfaces:
class IBaseNotification(Interface): subscribers = Attribute("List of subscribers") def notify(event): """Notify all subscribers of an event. """It is up to applications to supply subscribers by manipulating (appending to)
zope.event.subscribers.Zope will subscribe the following subscriber:
def dispatch(*event): for ignored in subscribers(event, None): passThis subscriber simply gets all of the "handlers" adapters for the event. A handler is a subscription adapter that is registered to provide
Noneand that does all it's work in it's factory function. Handlers are typically Python functions. (The `subscribers` method is provided by the adapter service.) Individual adapters may then get and call other adapters as needed (e.g. as described in http://dev.zope.org/Wikis/Zope3/InstanceAndTypeBasedSubscriptions.)The most important feature of the base notification system is that it does not dictate a policy. All base subscribers are called. If a specific policy (e.g. using filter functions) is needed, applications can add the policy by registering a new base subscriber, or, in Zope, by providing a specialized adapter.
- Because we will look up events as adapters, it won't be strictly necessary to define interfaces for events, since adapters can be registered for classes as well as interfaces.
- There won't be local subscription services. There will be
local adapter services and these will be able to handle local
subscriptions. This deserves some explanation.
We are assuming that, for now, all subscribers are software (bits of policy) because that's mostly all we've needed.
Consider an example. We currently have an object hub that subscribes to certain object events. It in turn can have subscribers that are catalogs or indexes. When an object is modified, an event is delivered to the local event service, which hands it off to the object hub. The hub transforms the event to a hub event and notifies its subscribers.
We will reimplement this in the following way. We'll have a subscriber that adapts object-modified events. This subscriber will find all of the catalogs and indexes (which are utilities) and call a reindex method on them. Each catalog or index will ask its hub (there might be several) for a hub id. If it gets one, then the index will update its information for the object.
It's possible and even likely that other subscriber models will be needed over time. The proposed model is simple enough that additional models can be built on it as needed without much difficulty.
Yay. --poster, 2004/04/08 15:09 EST reply
I like it. The last sentence is important to highlight: we may want channel subscribers and all kinds of different models. This proposal suggests that Zope X3 does not provide them, but enables them; and meanwhile, all of the system-level event-driven tasks that we have built so far can be accomplished with this simple model. Cool.
