Marcin Kasperski avatar Marcin Kasperski committed bbcad0e

defer_util works properly

Comments (0)

Files changed (1)

src/mekk/fics/twisted_util/defer_util.py

 """
 
 import logging
-from twisted.internet import defer, reactor
+from twisted.internet import defer, reactor, task
 
 logger = logging.getLogger("defer_util")
 
 def delay_succeed(reply, delay=0.01):
     """
     Similar to defer.succeed(reply), but introduces some minimal
-    delay before replying.
+    delay before replying. Also, cancel's itself in case deferred
+    is cancelled.
 
     This is most useful in tests, where it allows one to simulate
     mocked replies as truly async - but can also be used to force
     delays in processing.
+
+    Note: this is a simpler version of twisted.internet.task.deferLater
     """
-    d = defer.Deferred()
-    reactor.callLater(delay, d.callback, reply)
+    def cancelCallLater(deferred):
+        delayed_call.cancel()
+    d = defer.Deferred(cancelCallLater)
+    delayed_call = reactor.callLater(delay, d.callback, reply)
     return d
 
 def delay_exception(exception, delay=0.01):
     mocked replies as truly async - but can also be used to force
     delays in processing.
     """
-    d = defer.Deferred()
-    reactor.callLater(delay, d.errback, exception)
+    def cancelCallLater(deferred):
+        delayed_call.cancel()
+    d = defer.Deferred(cancelCallLater)
+    delayed_call = reactor.callLater(delay, d.errback, exception)
     return d
 
 class CancellingDeferredList(defer.DeferredList):
     Update to normal DeferredList: any failure causes all unfinished
     deferreds on the list to be cancelled.
 
-    This provides somewhat better completion semantics than normal
-    DeferredList in cases where deferreds on list are dependant and
-    caller syncs on list result without syncing on individual deferreds.
-    In such a scenario:
+    This is particularly useful when combined with task.deferLater,
+    delay_succeed, delay_exception and similar "clean properly after being cancelled"
+    deferreds, as it cleans the reactor from delayed calls on first failure without
+    the need to wait for all results (of which some may never arrive).
 
     - DeferredList(fireOnOneErrback=true) leaves reactor dirty as nobody
       awaits other results
     - DeferredList(fireOnOneErrback=false) may hang if some deferred
       is awaiting for failed one
-    - CancelingDeferredList fails after cancelling all unfinished deferreds
+    - CancelingDeferredList fails immediately and properly cleans up everything
+      (as long as deferreds in use have proper cancellers)
 
     Note: errback to it is not called, callback gets usual list of [(status, value-or-failure)]
     items. See gather_safely below for easier to use results.
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.