Liking cljdoc? Tell your friends :D

dev.zeko.stube.store

Pluggable persistence for conversation values.

A conversation is just a map of plain Clojure data (see dev.zeko.stube.conversation). Slice 3 adds a small protocol for swapping out the storage backend without touching the kernel:

(s/start! {:port  8080
           :store (dev.zeko.stube.store/file-store "/var/lib/stube/convs")})

Three operations are enough:

opwhen
load-allonce at startup, to repopulate memory
save!after every successful swap-conv!
delete!when a conversation ends (:end, reaper)

The default is in-memory-store, which keeps the slice-0 behaviour unchanged: the in-process atom in dev.zeko.stube.server is the only copy of the truth and save! is a no-op.

────────────────────────────────────────────────────────────────────── Cloroutine and persistence ──────────────────────────────────────────────────────────────────────

dev.zeko.stube.flow continuations are stateful objects, not EDN values. A conversation that contains a live defflow instance therefore can't go through the EDN file store as-is; the store will log a warning and skip that conversation. Hand-rolled task components from slice 0 (the :start + resume-key pattern) ARE EDN-clean and persist perfectly. Closing this gap is open work for a later slice.

Pluggable persistence for conversation values.

A conversation is just a map of plain Clojure data (see
[[dev.zeko.stube.conversation]]).  Slice 3 adds a small protocol for swapping
out the storage backend without touching the kernel:

    (s/start! {:port  8080
               :store (dev.zeko.stube.store/file-store "/var/lib/stube/convs")})

Three operations are enough:

| op           | when                                        |
|--------------|---------------------------------------------|
| `load-all`   | once at startup, to repopulate memory       |
| `save!`      | after every successful `swap-conv!`         |
| `delete!`    | when a conversation ends (`:end`, reaper)   |

The default is [[in-memory-store]], which keeps the slice-0 behaviour
unchanged: the in-process atom in `dev.zeko.stube.server` is the only copy of
the truth and `save!` is a no-op.

──────────────────────────────────────────────────────────────────────
Cloroutine and persistence
──────────────────────────────────────────────────────────────────────

`dev.zeko.stube.flow` continuations are stateful objects, not EDN values.  A
conversation that contains a live `defflow` instance therefore can't
go through the EDN file store as-is; the store will log a warning
and skip that conversation.  Hand-rolled task components from slice
0 (the `:start` + resume-key pattern) ARE EDN-clean and persist
perfectly.  Closing this gap is open work for a later slice.
raw docstring

ConversationStorecljprotocol

Backend for persisting conversation values. See namespace docstring.

Backend for persisting conversation values.  See namespace docstring.

delete!clj

(delete! this cid)

Remove the persisted conversation with id cid. Idempotent.

Remove the persisted conversation with id `cid`.  Idempotent.

load-allclj

(load-all this)

Return a map {cid → conv} of every persisted conversation. Called once at server startup before the http listener accepts requests.

Return a map `{cid → conv}` of every persisted conversation.
Called once at server startup before the http listener accepts
requests.

save!clj

(save! this conv)

Atomically replace the persisted value for (:conv/id conv). Returns conv on success. May log + return the conv unchanged on a non-fatal serialisation problem; should throw only on a backend-level failure (disk full, etc.).

Atomically replace the persisted value for `(:conv/id conv)`.
Returns `conv` on success.  May log + return the conv unchanged
on a non-fatal serialisation problem; should throw only on a
backend-level failure (disk full, etc.).
sourceraw docstring

file-storeclj

(file-store dir)

Persist every conversation as one EDN file in dir. The directory is created if it does not exist.

(file-store "./conv-store")

Files are named <cid>.edn. Writes go to a sibling temp file and are renamed atomically, so a crash mid-write never leaves a partial read on disk. Reads use clojure.edn/read-string with no eval and the default tagged-literal handler, so a corrupted file is the worst attacker reach.

If a conversation contains values that are not EDN-printable (the most common cause is a dev.zeko.stube.flow cloroutine continuation), the store logs a warning to *err* and skips the save without raising. The conversation stays live in memory; only its on-disk copy is stale.

Persist every conversation as one EDN file in `dir`.  The directory
is created if it does not exist.

    (file-store "./conv-store")

Files are named `<cid>.edn`.  Writes go to a sibling temp file and
are renamed atomically, so a crash mid-write never leaves a partial
read on disk.  Reads use `clojure.edn/read-string` with no eval and
the default tagged-literal handler, so a corrupted file is the worst
attacker reach.

If a conversation contains values that are not EDN-printable (the
most common cause is a `dev.zeko.stube.flow` cloroutine continuation), the
store logs a warning to `*err*` and *skips* the save without raising.
The conversation stays live in memory; only its on-disk copy is
stale.
sourceraw docstring

in-memory-storeclj

(in-memory-store)

The default store. Keeps no copy of its own — dev.zeko.stube.server's in-process atom IS the source of truth — and treats every operation as a no-op. Use this for tests, REPL iteration, and any deployment where you genuinely don't need crash-resume.

The default store.  Keeps no copy of its own — `dev.zeko.stube.server`'s
in-process atom IS the source of truth — and treats every operation
as a no-op.  Use this for tests, REPL iteration, and any deployment
where you genuinely don't need crash-resume.
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