[Twisted-Python] inlineCallbacks cascading cancelling and more

Sergey Magafurov smagafurov at naumen.ru
Tue Aug 17 01:49:32 EDT 2010


> First, generally: the most important thing to provide here are unit 
> tests with very clear documentation expressing why you would want 
> these things to work.  The test code you provided is unclear because 
> it does not succeed or fail, it just does some things, and then does 
> some other things, without explaining /why/ I would want to do those 
> things.  Given that the implementation of Deferred is changing a lot 
> now (see <http://twistedmatrix.com/trac/ticket/411>), if we agree with 
> your features, the implementation may have to change completely.  So, 
> it is important to have tests that describe just the behavior change, 
> not the implementation.
Agree! I precisely trying to suggest behavior, not the implementation :)
>> Wanted features:
>> 1. Ability to delete callbacks (delCallbacks)
>
> Can you please explain *why* you would want this?  Deleting callbacks 
> from a Deferred would break a lot of assumptions about the way that 
> Deferreds are used (at any particular point in the callback chain, you 
> should be able to infer what the return type should be just by looking 
> at the code, not running it).
>
> So, it is very unlikely that we will add the ability to delete 
> arbitrary callbacks.

>> 3. Ability to add/del hooks on deferred's finishing with errback 
>> or callback (addFinalizer/delFinalizer)
>
> You can already do this with weakref callbacks.  Why would you need 
> Deferred to provide an alternate mechanism?

I will try to explain why i want this features with example.
My task is about telephony.
Some user makes call and we want to acquire some TextToSpeach resource 
and AutomaticSpeachRecognition resource to do some automatic 
conversation with user.
We start playing music to user, launch long process to acquire this 
(expensive!) resources. After they have acquired, we establish audio 
links. After they established we speak something to user and start 
recognition. See NOTE in code.

@inlineCallbacks
def incoming_call(self, call):
     call.start_play('music')
     try:
         tts, asr = yield self.acquire_tts_for(call), 
self.acquire_asr_for(call) # tuple yield feature!
     except TimeoutError:
         # this occurs if TimeoutError raises in `self.acquire_tts_for` 
or `self.acquire_asr_for`
         # i.e. DeferredList(..., fireOnOneErrback=1)
         call.transfer_to('operator')
         # NOTE: at this point I want to automatically _recursively_ (to 
deep) stop all deferred processes
         # starting inside `self.acquire_tts_for` and `self.acquire_asr_for`
         # because I don't need their results (and expensive resources!) 
any more
     else:
         try:
             yield tts.speak('what you want? say me after signal')
             yield asr.start_recognition()
             call.start_play('signal')
             result = yield asr.wait_recognition_result()
             ... do something with result ...
         finally:
             tts.release()
             asr.release()

@inlineCallbacks
def acquire_tts_for(self, call):
     tts_connection = yield self.tts.acquire_connection(timeout=10) # 
may raise TimeoutError inside
     yield call.make_audio_link_with(tts_connection, 'in', timeout=10) # 
may raise TimeoutError inside
     return tts_connection

@inlineCallbacks
def acquire_asr_for(self, call):
     asr_connection = yield self.asr.acquire_connection(timeout=10) # 
may raise TimeoutError inside
     yield call.make_audio_link_with(asr_connection, 'out', timeout=10) 
# may raise TimeoutError inside
     return asr_connection

To do this code to work:
1. Deferred()s must have feature to be informed that somebody does't 
need their result any more (delCallbacks)
2. Deferred()s must track their usage, and automatically cancels (and 
therefore calls their finalizers, see below) when they not used any more 
(nobody needs their result any more)
3. inlineCallbacks must release (delCallbacks) their child Defered()s 
when it doesn't need their result any more, this allows them to 
autimatically cancelling (if they dont needed somebody else). To do this 
inlineCallbacks must add some hook (addFinalizer) to parent Deferred and 
release child Deferreds when parent Deferred finished 
(callbacked/errbacked and therefore cancelled due cancel call errback). 
Why we need addFinalizer mechanism? Because addCallbacks means that 
Deferred is used, that somebody needs their result. But addFinalizer 
means that we don't neeed result, we just want to know when Deferred 
finished (to release our child resources for example).

One more thing we may do with this features. What if our User hangs up 
call? What if our tcp connection lost (with that we have receive 
incoming call)? All resources (ASR and TTS) must be released as soon as 
possible! yields inside incoming_call must raise some ShuttingdownError 
for example. We may do this with above features.

>
> _______________________________________________
> Twisted-Python mailing list
> Twisted-Python at twistedmatrix.com
> http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
>    

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://twistedmatrix.com/pipermail/twisted-python/attachments/20100817/e8f38c30/attachment-0001.htm 


More information about the Twisted-Python mailing list