Description
The idiomatic way to "cancel" deferred in Manifold is to put an error value in order to short-circuit all chained listeners. Recently we had quite a few questions around this specific functionality... So, I wonder if it's better to have a public API in place to deal with cancellation? E.g.
;; define an exception class to be used in case we want to cancel a deferred
(d/CancelledException.)
;; equivalent to (d/error! d (d/CancelledException.))
(d/cancel! d)
;; or if I want to use my own subclass
(d/cancel! d (CustomCancelledException.))
;; to check if it was cancelled
(d/cancelled? d)
We also need to document that cancellation of d/future
or d/future-with
does not interrupt the underlying thread (which would be expected because of future-cancel
semantic from Clojure core).
More advanced thins in terms of cancellations:
- Versions of
d/zip
andd/alt
that propagate cancellation to underlying deferreds.
(let [ring1 (http/get "rings")
ring2 (http/get "rings")
ring3 (http/get "rings")
one-ring-to-rule-them-all (d/zip-cancellable ring1 ring2 ring3)]
;; cancel all 3 http requests, not only the result
(d/cancel! one-ring-to-rule-them-all))
It might be simple for 2 mentioned functions... but maybe we can think of a more general approach/solution where we can manually specify (or automatically derive?) a graph of connections between different deferred to use it to propagate CancelledExceptions
properly?
-
Keeping in mind previous item... should we treat
TimeoutException
as a cancellation? -
Self-referencial
cancelled?
checker ford/future
. That's arguable, but often times I need this:
(d/future
(dotimes [_ 100]
(when-not (am-I-cancelled?)
(do-something-useful))))
I'm not sure about this specific feature as it undercovers underlying mechanics to some extent. It's still doable by introducing a separate deferred in a lexical scope, but this approach might not be obvious for beginners. So, at least it should be well-documented.
@ztellman WDYT?