[PEAK] PEAK and Twisted, revisited
Phillip J. Eby
pje at telecommunity.com
Fri Apr 16 18:30:28 EDT 2004
At 04:59 PM 4/15/04 -0400, Stephen C. Waterbury wrote:
>>in PEAK you use the EventDriven Component as App-Component (or
>>subclasses of it) instead of Twistd. peak.event.Tasks are then
>>scheduled in the TwistedReactor that can use async io/deferreds
>Is there any example (preferably non-web) code for this?
>In particular, my application uses the usual Twisted chains of
>callbacks/errbacks ... have these been implemented or
>experimented with in a PEAK context?
See peak.events.twisted_support, which wraps Deferreds and the Twisted
reactor to look like their more flexible equivalents in peak.events.
In other words, if you want to write event-driven code that isn't a huge
chain of callbacks, you can instead write things like this:
... do some stuff
yield somethingReturningADeferred(); result = events.resume()
# result is now the *undeferred* result
... do other stuff
someTask = binding.Make(events.taskFactory(someTask), uponAssembly=True)
and do 'peak import:myapp.SomeApp' to run it. The main point here is that
'taskFactory' wraps a generator function so that instead of returning an
iterator, it returns an 'events.Task' object that will run as a
pseudothread in an event-driven program.
>I currently use Twisted's adbapi, and I don't see anything in
>PEAK like it (doesn't mean it's not there, of course ;).
You can of course use Twisted's adbapi when writing PEAK+Twisted programs,
subject of course to Twisted's own limitations. PEAK will eventually have
something like it, but the interface will be quite a bit different, in that
plain SQL will not be likely to play a significant part.
> It can
>use psycopg as its wrapped DBAPI driver, so might somehow
>be made to work with some existing peak.storage module.
No, sorry. peak.storage cannot be made to operate asynchronously, because
it relies on lazy loading of attributes. If you want to use peak.storage
inside an event-driven program, you'll need to use a threadpool (Twisted's
'reactor.runInThread()', I believe).
>Client | |Server
>------ | |------
>Domain /Log-\ / XMLRPC or\|wire, |/X \ /Log-\ /Services \
>Objs<->| ical | SOAP or |------| S | ical |(Repository,|
>| \API / \ PB/Banana/|ether,|\PB/ \API / \ etc.) /
>Local (etc) |etc |(etc)
>Persistence | |
>(ZODB) | |
>I apologize for the crudity of this model ...
>(Back To The Future fans: identify this quote! :)
>Nothing particularly earth-shaking or original here,
>of course -- this is just to provide context for my questions.
>Since we're currently using XML-RPC, I use a very simple transfer
>of state using dicts (xmlrpclib maps these to structs, of course, so
>that part is transparent). We have a local "registry" that supervises
>serialization/deserialization, making sure local instances are unique,
>and the most important domain objects are explicitly versioned
>(new version => new instance), with versioning being managed by the
>Repository service and understood by the client.
If new version == new instance, then presumably you would just include a
version ID in your OID scheme.
>I'm thinking a possible approach might be to implement the logical
>Repository API as a layer that would sit on top of a collection of
>datamanager API's -- perhaps an IVersioningDM that extends IWritableDM,
>and an ISQLQueryDM ...? The serialization API's for XML-RPC, SOAP, and
>PB could be backends to it on the client, frontends on the server.
>Does that make sense in PEAK API-space?
Yes. DM's are intended to mask storage implementation from code that
operates on domain-model objects. So, in principle you would have two DM
implementations for each kind of DM needed: one that operates on a physical
repository, and one that uses XML-RPC or whatever to access the repository
Note, however, that if your server needs to operate in an async manner, you
will need both a service area pool and a thread pool. The same might also
apply to your client software, if it needs to be asynchronous as well.
More information about the PEAK