[Zope3-dev] EventService, references, and subscription semantics

Jim Fulton jim@zope.com
Tue, 26 Feb 2002 16:54:29 -0500


Steve Alexander wrote:
> 
> This is an email to discuss various design decisions around the
> EventService.
> 
> At present there is checked into Zope3 a file-system level EventService,
>   which is configured by zcml files.
> An object can subscribe to this FS EventService, if it wants to receive
> events.
> The FS EventService keeps a list of subscribers, stored by python object
> reference.
> There is a zcml directive for subscribing a thing to the FS EventService.

IMPORTANT NOTE: The only reason we did a FS event service was to 
work around the fact that a TTW service manager wasn't working yet.
I didn't want to have to tie up a loose end in the sprint, so we
punted to the file system. We really should not worry much about the
semantics of a FS event service.

> Of course, if you subscribe something, and then restart z3.py, you have
> to resubscribe it. So, subscriptions are not persisted.

It depends on how you look at it. IMO, the subscriptions *are* persistent
via the zcml file. Every time you restart, you'll get the same subscriptions, 
unless you modify the zcml file, of course. 


> This makes it difficult for a persistent object (in the ZODB) to be a
> subscriber of the FS EventService, as it won't know when z3.py is
> restarted, so it won't know when it needs to resubscribe to the FS
> EventService.

Absolutely. Persistent objects can't subscribe to the FS event service.

> So, only non-persistent things can subscribe to the FS EventService.

Right, which makes the usefulness of the FS event service extremely limited
*except* as a prototype for the sprint.
 
> So, considering an FS EventService and a persistent ZODB EventService,
> we now have two distinct semantics for the subscribe() method:
> 
>    * a subscription that persists over server restarts
> 
>    * a subscription that is lost at server restart
> 
> However, there is only one interface. This needs fixing.

I don't agree. I think the interface is just fine, given the life-times
of the objects involved.
 
> Even if the FS EventService could store subscriptions between restarts
> of z3.py (for example, in a DBM file), how would it store the references
> to objects?

By direct references setup on restart by zcml processing.

...

> Let's say we have a persistent ZODB EventService. Persistent objects uss
> its subscribe() method to subscribe themselves to it.
> Well, FS services can't subscribe to it using that same method, because,
> even though the subscription is persisted between restarts, a singleton
> FS Service is an object attached to a module, and will be a brand new
> object each time z3.py restarts.

Right. The FS event service can't be a subscriber to a persistent
event service. Of course, it's not a subscriber anyway. Note that
event services usually propigate events to higher-level services, so
the FS event service can still get events.
 
> So, we'd need to have two distinct subscribe methods:
> 
>    * subscribe()  for persistent objects
> 
>    * transientSubscribe()  for non-persistent objects

No, you only need subscribe.
 
> And of course, some extra complexity in managing two collections of
> subscriptions.

Nah, only one kind of subscriptions.
 
> One solution would be to say that the FS EventService may only be
> subscribed to by non-persistent objects, and the root ZODB EventService
> may only be subscribed to by persistent objects.

Right.
 
> However, we'd need a separate interface for the FS EventService, as its
> subscribe() method would have different semantics than the persistent
> EventService.

I disagree. The semantics are the same. The lifetimes of the objects
are shorter, depending on how you define lifetime in this case.
 
> We could have something like this:
> 
>       ---------------------        ------------------
>       | IBaseEventService |        | ISubscribable  |
>       |===================|        |================|
>       | publishEvent      |        | subscribe      |
>       ---------------------        | unsubscribe    |
>                ^                   ------------------
>                |                          ^
>                |                          |
>                +-------------------+      |
>                |                   |      |
>       ------------------------    -------------------
>       | IFSEventService      |    | IEventService   |
>       |======================|    |=================|
>       | transientSubscribe   |    |                 |
>       | transientUnsubscribe |    -------------------
>       ------------------------
> 
> So, transient (ie non persisted) subscription is kept distinct from
> subscription that persists between z3.py invocations.
> FS things are only allowed to use the FSEventService.
> Most code that wants to use the event service will get it by asking for
> an IEventService. The root ZODB event service will propagate events to
> the FSEventService.

No, you don't need the transient version.
 
> Of course, it might turn out that we don't really need an
> FSEventService. Although, I can see it being useful for using the
> ComponentArchitecture outside of Zope3.

Yes.
 
> Then, we still have the issue of what to use for references.

Just use object addresses for FS event services.

There *is* an issue for persistent subscribables.

> We can use object references provided we're happy to only allow
> persistent objects to be passed to subscribe().
>
> We might want to have a range of subscribe methods:
> 
>    * subscribePersistentObject

Probably. There are complications with export and import, 
but exporting and imnporting event services is sufficiently
weird to begin with that I'm not inclined to worry too much about
it.
 
>    * subscribeTraversalLocation

This is probably a good idea. 

>    * subscribeTransientObject    (held onto by a weak reference perhaps)

No no no.
 
>    * subscribeRuidObject  (for subscribing an object via an object hub)

Yes. :)

It might be possible to abstract the subscribeTraversalLocation and subscribeRuidObject
cases. Let me think about that.
 
> Anyway, there's a bunch of thoughts and conclusions.
> 
> I'd really like to refactor the EventService along the lines of the UML
> diagram above, as I don't like having messy and conflicting semantics
> for interfaces.

I'd rather you didn't. I don't think it's 
 
Jim

--
Jim Fulton           mailto:jim@zope.com       Python Powered!        
CTO                  (888) 344-4332            http://www.python.org  
Zope Corporation     http://www.zope.com       http://www.zope.org