No vars found in this namespace.
No vars found in this namespace.
No vars found in this namespace.
No vars found in this namespace.
No vars found in this namespace.
No vars found in this namespace.
No vars found in this namespace.
No vars found in this namespace.
No vars found in this namespace.
No vars found in this namespace.
Helpers for enriching envelopes with standardized DLQ metadata.
The canonical location for DLQ state is:
[:metadata :dlq]This metadata is designed to be portable across sinks (logger/storage/producer) and across replay mechanisms.
Helpers for enriching envelopes with standardized DLQ metadata. The canonical location for DLQ state is: - `[:metadata :dlq]` This metadata is designed to be portable across sinks (logger/storage/producer) and across replay mechanisms.
No vars found in this namespace.
No vars found in this namespace.
No vars found in this namespace.
Schema helpers for D-core.
This module provides:
validate!, valid?) throwing typed, non-retriable exceptionstemporal) and WIRE <-> SYSTEM coercion
(coerce!, coerce, ->wire!, ->wire, temporal-transformer) (roadmap 02, B6).Schema helpers for D-core. This module provides: - Strictness (:strict/:lax) application to Malli map schemas (:closed true/false) - Validation (`validate!`, `valid?`) throwing typed, non-retriable exceptions - Temporal schema constructors (`temporal`) and WIRE <-> SYSTEM coercion (`coerce!`, `coerce`, `->wire!`, `->wire`, `temporal-transformer`) (roadmap 02, B6).
No vars found in this namespace.
No vars found in this namespace.
C1 — Backoff policies as pure functions.
Every policy returns a plain fn of attempt → delay in milliseconds, where
attempt is the 1-based failure count ((retry-fn 1) is the delay after
the first failure). This matches the contract d-core.libs.retriable
already documents.
Delays are always long milliseconds. This is the settled decision for
this pillar: it matches d-core.libs.retriable (Thread/sleep), and it maps
onto both existing ecosystem implementations with no conversion, which is what
makes their migration provably behaviour-preserving (see
backoff-test/matches-async-proxy-compute-backoff-ms and
backoff-test/matches-http-calc-backoff-ms). java.time.Duration remains the
vocabulary of Pillar A at the boundary; this policy layer stays in ms.
:jitter accepts either a keyword or a number:
| Value | Distribution |
|---|---|
:none | no jitter — fully deterministic |
:full | uniform [0, d) — AWS "full jitter" |
:equal | uniform [d/2, d) — AWS "equal jitter" |
<number> k | uniform [d-(k·d), d+(k·d)] — symmetric/proportional |
The numeric form exists because it is exactly what
d-core-http/.../client.clj already does with :jitter 0.2, so that call
site can migrate without changing its observed delay distribution.
:rand-fn is an injection point (a 0-arg fn returning [0.0, 1.0), default
rand). It is mandatory whenever jitter is active — a jittered policy
without it would be untestable, and silently defaulting would make the
dependency invisible at the call site.
:max-ms caps the delay before jitter is applied. Consequently:
:none, :full or :equal, the observed delay never exceeds the cap
(:full is in fact strictly below it);k, the observed delay is bounded by
max-ms · (1 + k), i.e. the cap bounds the jitter centre, not the
absolute ceiling. This is deliberate: it is the behaviour of the existing
d-core-http implementation, and changing it would change the retry
envelope of a live client.exponential-backoff, linear-backoff and constant-backoff are pure: the
returned fn depends only on its attempt argument.
decorrelated-jitter is inherently stateful (its next delay depends on the
previous draw, not on attempt), so it is deliberately not an
attempt -> ms fn. It is exposed as a pure state transducer — see its
docstring — rather than bending the common contract and hiding an atom.
C1 — Backoff policies as pure functions. Every policy returns a plain fn of `attempt` → delay in milliseconds, where `attempt` is the **1-based failure count** (`(retry-fn 1)` is the delay after the first failure). This matches the contract `d-core.libs.retriable` already documents. ## Units Delays are **always `long` milliseconds**. This is the settled decision for this pillar: it matches `d-core.libs.retriable` (`Thread/sleep`), and it maps onto both existing ecosystem implementations with no conversion, which is what makes their migration provably behaviour-preserving (see `backoff-test/matches-async-proxy-compute-backoff-ms` and `backoff-test/matches-http-calc-backoff-ms`). `java.time.Duration` remains the vocabulary of Pillar A at the *boundary*; this policy layer stays in ms. ## Jitter `:jitter` accepts either a keyword or a number: | Value | Distribution | | :----------- | :-------------------------------------------------- | | `:none` | no jitter — fully deterministic | | `:full` | uniform `[0, d)` — AWS "full jitter" | | `:equal` | uniform `[d/2, d)` — AWS "equal jitter" | | `<number> k` | uniform `[d-(k·d), d+(k·d)]` — symmetric/proportional | The numeric form exists because it is exactly what `d-core-http/.../client.clj` already does with `:jitter 0.2`, so that call site can migrate without changing its observed delay distribution. `:rand-fn` is an injection point (a 0-arg fn returning `[0.0, 1.0)`, default `rand`). It is **mandatory whenever jitter is active** — a jittered policy without it would be untestable, and silently defaulting would make the dependency invisible at the call site. ## Cap semantics `:max-ms` caps the delay *before* jitter is applied. Consequently: - with `:none`, `:full` or `:equal`, the observed delay never exceeds the cap (`:full` is in fact strictly below it); - with numeric jitter `k`, the observed delay is bounded by `max-ms · (1 + k)`, i.e. the cap bounds the jitter *centre*, not the absolute ceiling. This is deliberate: it is the behaviour of the existing `d-core-http` implementation, and changing it would change the retry envelope of a live client. ## Purity `exponential-backoff`, `linear-backoff` and `constant-backoff` are pure: the returned fn depends only on its `attempt` argument. `decorrelated-jitter` is *inherently stateful* (its next delay depends on the previous draw, not on `attempt`), so it is deliberately **not** an `attempt -> ms` fn. It is exposed as a pure state transducer — see its docstring — rather than bending the common contract and hiding an atom.
Railway-oriented CSP pipeline for Clojure core.async.
Stages execute in sequence; successful results pass to the next stage's
input channel, while any failure (thrown exception or error return value)
is immediately routed to a consolidated error channel. Returning nil
filters/drops the item.
Railway-oriented CSP pipeline for Clojure core.async. Stages execute in sequence; successful results pass to the next stage's input channel, while any failure (thrown exception or error return value) is immediately routed to a consolidated error channel. Returning `nil` filters/drops the item.
Compact, high-signal stack traces (Roadmap 05, idea D1).
A failed assertion or exception usually produces a wall of java.*, clojure.lang.*,
nREPL and generated invokeStatic frames, burying the two frames that actually name your
code. This namespace is split hard between classification and printing:
frame-category and interesting-frame?
answer "is this frame mine?" from plain data, no exceptions required;clean-stacktrace returns the surviving frames (never truncates);format-stacktrace renders them, eliding the middle so the throw site and the
entry point stay visible.Detail level resolves as: explicit :detail/:max-frames opts > *stacktrace-detail*
D_CORE_STACKTRACE_DETAILenv var >:normal.
Filters are overridable per call via :keep / :drop predicates over a normalized frame
map, so nobody debugging clojure.lang internals is stuck with our taste.
Your own code is recognised by namespace prefix. d_core/d-core are built in; a different
project registers its prefix once, with no code required:
D_CORE_PROJECT_NS=my-app,my-app-workers clojure -M:test
or at runtime with register-project-ns!, or per call with :extra-project.
Compact, high-signal stack traces (Roadmap 05, idea D1).
A failed assertion or exception usually produces a wall of `java.*`, `clojure.lang.*`,
nREPL and generated `invokeStatic` frames, burying the two frames that actually name your
code. This namespace is split hard between *classification* and *printing*:
- classification is pure and table-driven: [[frame-category]] and [[interesting-frame?]]
answer "is this frame mine?" from plain data, no exceptions required;
- [[clean-stacktrace]] returns the surviving frames (never truncates);
- [[format-stacktrace]] renders them, eliding the middle so the throw site *and* the
entry point stay visible.
Detail level resolves as: explicit `:detail`/`:max-frames` opts > [[*stacktrace-detail*]]
> `D_CORE_STACKTRACE_DETAIL` env var > `:normal`.
Filters are overridable per call via `:keep` / `:drop` predicates over a normalized frame
map, so nobody debugging `clojure.lang` internals is stuck with our taste.
Your own code is recognised by namespace prefix. `d_core`/`d-core` are built in; a different
project registers its prefix once, with no code required:
D_CORE_PROJECT_NS=my-app,my-app-workers clojure -M:test
or at runtime with [[register-project-ns!]], or per call with `:extra-project`.The temporal contract (roadmap 02, B1/B4/B5).
Two vocabularies, deliberately separate:
Domains are the internal representation. Everything internal is UTC:
a point in time is a java.time.Instant, a span is a java.time.Duration,
and :local-date is a civil date that is deliberately not a point in time.
Zone-bearing and wall-clock types (:local-date-time, :zoned-date-time,
:offset-date-time) are ingress formats only — they are resolved to an
Instant at the boundary and never travel internally (D10).
Dialects are the encodings used at a boundary. A dialect is a named
value (or explicit ingress map), chosen explicitly, never inferred (D6).
:epoch-ms is the platform default for :instant (D3b) and :millis for
:duration.
The temporal contract (roadmap 02, B1/B4/B5). Two vocabularies, deliberately separate: - **Domains** are the *internal* representation. Everything internal is UTC: a point in time is a `java.time.Instant`, a span is a `java.time.Duration`, and `:local-date` is a civil date that is deliberately *not* a point in time. Zone-bearing and wall-clock types (`:local-date-time`, `:zoned-date-time`, `:offset-date-time`) are **ingress formats only** — they are resolved to an `Instant` at the boundary and never travel internally (D10). - **Dialects** are the *encodings* used at a boundary. A dialect is a named value (or explicit ingress map), chosen explicitly, never inferred (D6). `:epoch-ms` is the platform default for `:instant` (D3b) and `:millis` for `:duration`.
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 |