Liking cljdoc? Tell your friends :D

com.blockether.vis.ext.language-clojure.nrepl-client

Thin, observable nREPL client for clj/eval.

Connection model:

  • One nrepl.core/connect socket per [host port] key, cached on a defonce atom so we survive (require :reload) during development.
  • ONE long-lived nREPL session per connection, cloned lazily on first use and cached beside the socket — then REUSED by every eval!. This is how Cider/Calva/every editor drives nREPL: no per-eval clone/close round-trip on the hot path (those were what blew the native-tool timeout budget under JVM load), nothing to leak, and session-local state — *1/*2/*3/*e and dynamic set!s — PERSISTS across calls like a real REPL ((def …) was already global; now the whole session is).
  • Stale / closed sockets are detected (IOException / nil message stream) and the entry is evicted — closing the socket and dropping the cached session — so the next call re-dials + re-clones.

Returned shape (success) — STRING keys (crosses the strings-only boundary as a tool :result; enrichment adds "error_message"/"error_data"/"trace"): {"value" "42" ; pr-str of the LAST form's value, or nil "values" ["1" "42"] ; pr-str of every emitted value "out" "hello\n" ; stdout aggregated "err" "" ; stderr aggregated "ns" "user" ; final ns name "status" #{"done"} ; nREPL status set (strings) "ex" nil ; exception class name, when status :ex "root_ex" nil ; root exception class name "ms" 12 ; wall-clock duration "port" 7888 "timed_out" false}

Failure paths throw ex-info with :type :clj/nrepl-* so the Vis tool wrapper can surface a clean error to the model.

Thin, observable nREPL client for `clj/eval`.

Connection model:
  * One `nrepl.core/connect` socket per `[host port]` key, cached
    on a `defonce` atom so we survive `(require :reload)` during
    development.
  * ONE long-lived nREPL session per connection, cloned lazily on
    first use and cached beside the socket — then REUSED by every
    `eval!`. This is how Cider/Calva/every editor drives nREPL: no
    per-eval `clone`/`close` round-trip on the hot path (those were
    what blew the native-tool timeout budget under JVM load), nothing
    to leak, and session-local state — `*1`/`*2`/`*3`/`*e` and dynamic
    `set!`s — PERSISTS across calls like a real REPL (`(def …)` was
    already global; now the whole session is).
  * Stale / closed sockets are detected (`IOException` / `nil`
    message stream) and the entry is evicted — closing the socket and
    dropping the cached session — so the next call re-dials + re-clones.

Returned shape (success) — STRING keys (crosses the strings-only boundary
as a tool `:result`; enrichment adds "error_message"/"error_data"/"trace"):
  {"value"      "42"          ; pr-str of the LAST form's value, or nil
   "values"     ["1" "42"]   ; pr-str of every emitted value
   "out"        "hello\n"     ; stdout aggregated
   "err"        ""             ; stderr aggregated
   "ns"         "user"         ; final *ns* name
   "status"     #{"done"}      ; nREPL status set (strings)
   "ex"         nil              ; exception class name, when status :ex
   "root_ex"    nil              ; root exception class name
   "ms"         12               ; wall-clock duration
   "port"       7888
   "timed_out" false}

Failure paths throw `ex-info` with `:type :clj/nrepl-*` so the
Vis tool wrapper can surface a clean error to the model.
raw docstring

close-all!clj

(close-all!)

Close every cached connection. Idempotent. Useful from tests / doctor / shutdown hooks.

Close every cached connection. Idempotent. Useful from
tests / doctor / shutdown hooks.
sourceraw docstring

eval!clj

(eval! {:keys [host port code ns timeout-ms pretty? print-margin]
        :or {host "localhost" timeout-ms 30000 print-margin 100}})

Evaluate code in the nREPL at host:port. Opts: :host defaults to "localhost" :ns starting namespace, e.g. "user" :timeout-ms default 30000 :pretty? when true, ask nREPL's print middleware to pretty-print the value(s) SERVER-SIDE via nrepl.util.print/pprint — so the live object is formatted where it lives (handles unreadable objects / lazy seqs) and :value/:values come back as multi-line, indented text. Output stays valid EDN. :print-margin right-margin columns for pretty printing (default 100)

Always returns a map (see ns docstring). Connection failures throw :clj/nrepl-connect-failed; everything else (eval error, timeout) is reported inside the returned map so the model can read it as data.

Evaluate `code` in the nREPL at `host:port`. Opts:
  :host        defaults to "localhost"
  :ns          starting namespace, e.g. "user"
  :timeout-ms  default 30000
  :pretty?     when true, ask nREPL's print middleware to pretty-print the
               value(s) SERVER-SIDE via `nrepl.util.print/pprint` — so the
               live object is formatted where it lives (handles unreadable
               objects / lazy seqs) and `:value`/`:values` come back as
               multi-line, indented text. Output stays valid EDN.
  :print-margin  right-margin columns for pretty printing (default 100)

Always returns a map (see ns docstring). Connection failures
throw `:clj/nrepl-connect-failed`; everything else (eval error,
timeout) is reported inside the returned map so the model can
read it as data.
sourceraw docstring

evict!clj

(evict! host port)

Drop the cached connection (and its long-lived session) for [host port], CLOSING the socket so BOTH sides let go: the server reaps the session's executor thread and OUR client transport thread dies instead of parking forever. Call it whenever a REPL at [host port] goes away (stop, reap, crash) — a cache entry outliving its process leaks one thread + one socket per REPL. The next call re-dials and re-clones.

Drop the cached connection (and its long-lived session) for `[host port]`,
CLOSING the socket so BOTH sides let go: the server reaps the session's
executor thread and OUR client transport thread dies instead of parking
forever. Call it whenever a REPL at `[host port]` goes away (stop, reap,
crash) — a cache entry outliving its process leaks one thread + one socket
per REPL. The next call re-dials and re-clones.
sourceraw docstring

health-check!clj

(health-check! {:keys [host port timeout-ms]
                :or {host "localhost" timeout-ms 2000}})

REAL eval-based health check — the strong signal probe!'s describe can't give. Runs (+ 1 1) through a DEDICATED health session on the cached connection under a SHORT timeout and confirms it returns "2". describe only proves the accept loop answers; this proves the JVM actually EVALUATES code, so a wedged eval executor / blocked compile lock is caught even while describe still replies. Returns:

{:status :up :ms N} — evaluated "2" cleanly; the eval path is healthy. {:status :unresponsive :form "(+ 1 1)" :ms N :hint "..."} — connected but the eval TIMED OUT or didn't return "2": the REPL is wedged and should be killed & restarted (or reprobed). {:status :down :form "(+ 1 1)"} — could not connect (stale .nrepl-port / dead process).

Uses a SEPARATE session so it never clobbers the user session's *1/*2/*3. Never throws. On a hard socket error the connection is evicted so the next call reconnects fresh.

REAL eval-based health check — the strong signal `probe!`'s `describe` can't
give. Runs `(+ 1 1)` through a DEDICATED health session on the cached
connection under a SHORT timeout and confirms it returns `"2"`. `describe`
only proves the accept loop answers; this proves the JVM actually EVALUATES
code, so a wedged eval executor / blocked compile lock is caught even while
`describe` still replies. Returns:

  {:status :up           :ms N}
    — evaluated `"2"` cleanly; the eval path is healthy.
  {:status :unresponsive :form "(+ 1 1)" :ms N :hint "..."}
    — connected but the eval TIMED OUT or didn't return `"2"`: the REPL is
      wedged and should be killed & restarted (or reprobed).
  {:status :down         :form "(+ 1 1)"}
    — could not connect (stale `.nrepl-port` / dead process).

Uses a SEPARATE session so it never clobbers the user session's
`*1`/`*2`/`*3`. Never throws. On a hard socket error the connection is evicted
so the next call reconnects fresh.
sourceraw docstring

health-formclj

The canonical liveness eval: cheap, pure, and an unmistakable "2" result.

The canonical liveness eval: cheap, pure, and an unmistakable `"2"` result.
sourceraw docstring

probe!clj

(probe! {:keys [host port timeout-ms] :or {host "localhost" timeout-ms 100}})

Best-effort liveness probe for the nREPL at host:port. Sends a single describe op (no code execution) under a SHORT timeout and classifies:

{:status :up :versions {:clojure ..} :dialect :clj|:cljs :cwd "/path"} — connected and the server answered describe. {:status :unresponsive} — socket opened but no clean describe reply in budget. {:status :down} — could not connect (stale .nrepl-port, dead proc).

:dialect (clj vs cljs) is read from the describe metadata; :cwd is the server JVM's working directory via one tiny eval (nil when unavailable). Both are best-effort and only present when :up.

Never throws. Reuses the cached connection (warming the same pool eval! uses). The short :timeout-ms (default 100) is passed to nrepl/client, which bounds each response read regardless of the cached connection's transport timeout.

Best-effort liveness probe for the nREPL at `host:port`. Sends a single
`describe` op (no code execution) under a SHORT timeout and classifies:

  {:status :up :versions {:clojure ..} :dialect :clj|:cljs :cwd "/path"}
                      — connected and the server answered describe.
  {:status :unresponsive}
                      — socket opened but no clean describe reply in budget.
  {:status :down}     — could not connect (stale `.nrepl-port`, dead proc).

`:dialect` (clj vs cljs) is read from the describe metadata; `:cwd` is the
server JVM's working directory via one tiny eval (nil when unavailable).
Both are best-effort and only present when `:up`.

Never throws. Reuses the cached connection (warming the same pool
`eval!` uses). The short `:timeout-ms` (default 100) is passed to
`nrepl/client`, which bounds each response read regardless of the
cached connection's transport timeout.
sourceraw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close