User-facing API for dj.concurrency: create and drive a supervisor, submit work, and inspect/intervene from the REPL.
The library is split into a functional core and an imperative shell:
dj.concurrency.shell — the impure runtime (event queue, virtual
threads, directive interpreter, the future handle)dj.concurrency.policy — the pure reference policy (the state machine)
This namespace is the thin facade over both; requiring it is all you need.Return-value style: every function here returns a MAP, except the two data
shapes that are intrinsically positional pairs and travel through the
queue/policy verbatim — events [event-type payload] and directives
[directive-type payload].
User-facing API for dj.concurrency: create and drive a supervisor, submit
work, and inspect/intervene from the REPL.
The library is split into a functional core and an imperative shell:
- `dj.concurrency.shell` — the impure runtime (event queue, virtual
threads, directive interpreter, the future handle)
- `dj.concurrency.policy` — the pure reference policy (the state machine)
This namespace is the thin facade over both; requiring it is all you need.
Return-value style: every function here returns a MAP, except the two data
shapes that are intrinsically positional pairs and travel through the
queue/policy verbatim — events `[event-type payload]` and directives
`[directive-type payload]`.Functional core for dj.concurrency: the pure reference policy that decides
what should happen, with no side effects. The impure execution of those
decisions lives in dj.concurrency.shell.
A policy is a pure function (fn [event state] -> {:directives [...] :state s'}).
Events and directives are positional pairs [type payload-map]; every other
value is a MAP so the code reads by key rather than by position.
NOTE: the qualified keywords :dj.concurrency/attempts,
:dj.concurrency/max-attempts, and :dj.concurrency/shutdown are part of the
public contract — consumers set :dj.concurrency/max-attempts in a task's
context and match on :dj.concurrency/shutdown in ex-data. They are keyed to
the dj.concurrency namespace, so they are written out in full here rather
than with :: auto-resolution (which would key them to THIS namespace).
Functional core for dj.concurrency: the pure reference policy that decides
what should happen, with no side effects. The impure execution of those
decisions lives in `dj.concurrency.shell`.
A policy is a pure function `(fn [event state] -> {:directives [...] :state s'})`.
Events and directives are positional pairs `[type payload-map]`; every other
value is a MAP so the code reads by key rather than by position.
NOTE: the qualified keywords `:dj.concurrency/attempts`,
`:dj.concurrency/max-attempts`, and `:dj.concurrency/shutdown` are part of the
public contract — consumers set `:dj.concurrency/max-attempts` in a task's
context and match on `:dj.concurrency/shutdown` in ex-data. They are keyed to
the `dj.concurrency` namespace, so they are written out in full here rather
than with `::` auto-resolution (which would key them to THIS namespace).Imperative shell for dj.concurrency: the impure runtime that owns the event
queue, spawns virtual threads, and interprets directives. Everything with a
side effect lives here; the pure decision-making lives in
dj.concurrency.policy.
The shell communicates with the policy through two positional pairs that travel across the queue verbatim:
NOTE: the qualified keyword :dj.concurrency/shutdown is part of the public
contract (consumers match on (:type (ex-data e))). It is keyed to the
dj.concurrency namespace, so it is written out in full rather than with
:: auto-resolution (which would key it to THIS namespace).
Imperative shell for dj.concurrency: the impure runtime that owns the event queue, spawns virtual threads, and interprets directives. Everything with a side effect lives here; the pure decision-making lives in `dj.concurrency.policy`. The shell communicates with the policy through two positional pairs that travel across the queue verbatim: - events [event-type payload-map] - directives [directive-type payload-map] Every other value here is a MAP (policy results, internal shell bindings) so the code reads by key rather than by position. NOTE: the qualified keyword `:dj.concurrency/shutdown` is part of the public contract (consumers match on `(:type (ex-data e))`). It is keyed to the `dj.concurrency` namespace, so it is written out in full rather than with `::` auto-resolution (which would key it to THIS namespace).
Pluggable durable result store for task memoization.
A task opts in with :dj.concurrency/durable-key in its context; a supervisor opts in with a :store satisfying ResultStore. Both absent => behavior identical to a supervisor without this feature.
Keys are EDN data, stored VERBATIM. There is deliberately no hashing/
digesting step: keeping the literal key in the journal keeps it
introspectable (you can read a results.edn and see exactly which
inputs produced which results). Clojure value-equality on the key data
is what makes a re-run a hit, so map key order is irrelevant to
equality. Derive your own keys from a task's inputs — e.g.
[:summarize prompt].
Pluggable durable result store for task memoization. A task opts in with :dj.concurrency/durable-key in its context; a supervisor opts in with a :store satisfying ResultStore. Both absent => behavior identical to a supervisor without this feature. Keys are EDN data, stored VERBATIM. There is deliberately no hashing/ digesting step: keeping the literal key in the journal keeps it introspectable (you can read a `results.edn` and see exactly which inputs produced which results). Clojure value-equality on the key data is what makes a re-run a hit, so map key order is irrelevant to equality. Derive your own keys from a task's inputs — e.g. `[:summarize prompt]`.
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 |