Cancellation token - leaf module.
The cancellation token is a tiny two-atom record that lets a UI
thread (TUI, Telegram bot, REPL caller) cooperatively abort an
in-flight turn! AND interrupt the worker future hosting the
blocking provider call. The cooperative side is checked at every
iteration boundary; the future side hard-cancels any HTTP call
that has already started.
Public API:
(cancellation-token) - fresh token
(cancellation-atom token) - cooperative flag atom (pass to turn!)
(cancellation-set-future! token fut) - register the worker future
(cancel! token) - set flag + interrupt registered future
(cancelled? token) - true once cancel! has been called
(cancellation? throwable) - true if exception was caused by cancel!
This namespace has zero side effects at load time and depends only on Java interop - channels and the runtime can require it directly without pulling in the rest of the SDK.
Cancellation token - leaf module. The cancellation token is a tiny two-atom record that lets a UI thread (TUI, Telegram bot, REPL caller) cooperatively abort an in-flight `turn!` AND interrupt the worker future hosting the blocking provider call. The cooperative side is checked at every iteration boundary; the future side hard-cancels any HTTP call that has already started. Public API: `(cancellation-token)` - fresh token `(cancellation-atom token)` - cooperative flag atom (pass to `turn!`) `(cancellation-set-future! token fut)` - register the worker future `(cancel! token)` - set flag + interrupt registered future `(cancelled? token)` - true once `cancel!` has been called `(cancellation? throwable)` - true if exception was caused by `cancel!` This namespace has zero side effects at load time and depends only on Java interop - channels and the runtime can require it directly without pulling in the rest of the SDK.
(cancel! token)Abort the in-flight turn. Flips the cooperative flag AND runs every
registered on-cancel! callback. Each callback is wrapped in its
own try/catch so one bad consumer cannot starve the rest.
Safe to call multiple times — on the second call the flag is
already set, and the callback list has typically drained because
workers disposed themselves.
Abort the in-flight turn. Flips the cooperative flag AND runs every registered `on-cancel!` callback. Each callback is wrapped in its own `try`/`catch` so one bad consumer cannot starve the rest. Safe to call multiple times — on the second call the flag is already set, and the callback list has typically drained because workers disposed themselves.
(cancellation-atom token)Cooperative flag atom — read with @ at iteration boundaries when
the consumer can return without external help.
Cooperative flag atom — read with `@` at iteration boundaries when the consumer can return without external help.
(cancellation-set-future! token fut)Register a worker Future so cancel! interrupts it. Thin
convenience over on-cancel!: wraps .cancel(true) in a thunk
and discards the returned dispose! (the future's own completion
makes the second cancel a no-op).
Returns the future for convenient threading.
Register a worker `Future` so `cancel!` interrupts it. Thin convenience over `on-cancel!`: wraps `.cancel(true)` in a thunk and discards the returned `dispose!` (the future's own completion makes the second cancel a no-op). Returns the future for convenient threading.
(cancellation-token)Construct a fresh cancellation token.
The token bundles two things every cancellable boundary needs:
::flag — cooperative boolean atom, polled at iteration
boundaries by callers that can return
gracefully.::callbacks — vec of [id thunk] pairs run by cancel! so
any number of in-flight workers (provider
HTTP call, Python eval future, voice recorder)
can register their own hard-cancel hook.cancellation-set-future! (legacy single-future API) is kept for
call sites that have not migrated yet; it now routes through the
callback registry too so behaviour stays identical.
Construct a fresh cancellation token.
The token bundles two things every cancellable boundary needs:
- `::flag` — cooperative boolean atom, polled at iteration
boundaries by callers that can return
gracefully.
- `::callbacks` — vec of `[id thunk]` pairs run by `cancel!` so
any number of in-flight workers (provider
HTTP call, Python eval future, voice recorder)
can register their own hard-cancel hook.
`cancellation-set-future!` (legacy single-future API) is kept for
call sites that have not migrated yet; it now routes through the
callback registry too so behaviour stays identical.(cancellation? e)True if the given throwable was caused by a cancel! call. Channels
should treat this as a normal (cancelled) outcome rather than an
error and avoid showing stack traces.
True if the given throwable was caused by a `cancel!` call. Channels should treat this as a normal (cancelled) outcome rather than an error and avoid showing stack traces.
(cancelled? token)True once cancel! has been called on this token.
True once `cancel!` has been called on this token.
(on-cancel! token thunk)Register a no-arg thunk to fire the moment cancel! is invoked
on token. Returns a dispose! thunk the caller MUST invoke when
the cancellable work finishes normally — otherwise callbacks
accumulate for the token's lifetime.
If cancel! has already fired on this token, thunk runs
synchronously here and dispose! is a no-op. This matches the
contract every consumer wants: registering AFTER cancellation
must still cancel, not silently swallow the request.
Replaces the atom-watch pattern earlier eval boundaries hand-rolled: one shared callback list, no per-consumer add-watch / remove-watch plumbing, no risk of leaving a watch on the flag after the worker finishes.
Register a no-arg `thunk` to fire the moment `cancel!` is invoked on `token`. Returns a `dispose!` thunk the caller MUST invoke when the cancellable work finishes normally — otherwise callbacks accumulate for the token's lifetime. If `cancel!` has already fired on this token, `thunk` runs synchronously here and `dispose!` is a no-op. This matches the contract every consumer wants: registering AFTER cancellation must still cancel, not silently swallow the request. Replaces the atom-watch pattern earlier eval boundaries hand-rolled: one shared callback list, no per-consumer add-watch / remove-watch plumbing, no risk of leaving a watch on the flag after the worker finishes.
(virtual-threads-available?)True when this JVM exposes Java virtual-thread APIs. Reflection keeps source compatible with older runtimes.
True when this JVM exposes Java virtual-thread APIs. Reflection keeps source compatible with older runtimes.
(worker-future f)(worker-future name f)Run f on a cancellable worker Future. Uses a virtual thread when the JVM
supports it, otherwise falls back to a named daemon platform thread.
The returned value implements java.util.concurrent.Future plus Clojure
deref/realized? protocols so legacy future call sites can migrate without
losing timeout/cancellation behavior.
Run `f` on a cancellable worker Future. Uses a virtual thread when the JVM supports it, otherwise falls back to a named daemon platform thread. The returned value implements java.util.concurrent.Future plus Clojure deref/realized? protocols so legacy `future` call sites can migrate without losing timeout/cancellation behavior.
(worker-runtime)Runtime probe for worker execution. :worker-helper is stable metadata for
diagnostics; :virtual-threads? reports whether new worker tasks will use
Java virtual threads.
Runtime probe for worker execution. `:worker-helper` is stable metadata for diagnostics; `:virtual-threads?` reports whether new worker tasks will use Java virtual threads.
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |