[Twisted-Python] inlineCallbacks cascading cancelling and more
Sergey Magafurov
smagafurov at naumen.ru
Mon Aug 16 23:49:32 MDT 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: </pipermail/twisted-python/attachments/20100817/e8f38c30/attachment.html>
More information about the Twisted-Python
mailing list