All notable changes to logdb_client are documented here.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning. While the major version is 0, a minor bump (0.x.0) may break the API; a patch (0.x.y) never does. How a release is made: RELEASING.md.
Unreleased
0.3.0 - 2026-10-10
Everything since 0.2.11, the previous version on hex (0.2.12 and 0.2.13 were never published).
The public API is the same — use LogDB.Client.Consumer, LogDB.Client.Supervisor,
LogDB.publish/4 and friends — but reply shapes and option checks changed; see
Upgrading from 0.2 below.
Added
- Connection string:
logdb[s]://[token@]host[:port][/stream/consumer][?transport=…&node=…&client=…](LogDB.Client.ConnectionString, spec indocs/connection-string.md). The token may also come astoken:; anything set both ways must agree. Default port 4000 (443 withlogdbs). LogDB.Error— one error for every transport:{:error, %LogDB.Error{code, message, details}}. It is an exception, soraise errorworks.- Client API 1 (
hello): the client names itself (client_name:, default — node or host name) and negotiates the API with the bus; the LogDB console shows which instance is connected. consumer: "stream/name"for every transport — the service is known from the token. The oldstream:+consumer_id:pair still works.- HTTP delivery: long-poll from a pull consumer (
/v1/events/poll), the next batch only after the consumer has handled the previous one. - WebSocket is self-sufficient: publish, subscribe, ack/nack/term/progress and ping over one
socket; every command waits for the bus's reply (
request_id). - Confirmations:
LogDB.term/3(never deliver again),LogDB.nack/3withdelay_ms:,LogDB.progress/2(resetack_waitduring long handling);{:term, st}and{:nack, st, delay_ms: n}replies fromhandle_event/4. - Payload types: the publisher declares
_content_type; over erlangd the parser encodes bytes (encode_bytes/1).Parser.Autodecodes by the declared type. LogDB.await_connected/2;init_arg:option for the consumer's own data; the child id is the client's name, so several clients fit in one supervisor.
Changed
Reply shapes: commands return `{:ok, result} } ,subscribe` andpingreturn `:ok}`, on every transport. Errors used to be {status, body},{code, message},{string, index},{:exit, r}or bare atoms. HTTP returns the bus's body instead of%Req.Response{}; erlangd publish results have the WS/HTTP shape (%{"result" => [...], "failed" => n}).- A single
publishthe bus refused (no stream, JetStream refusal) is{:error, %LogDB.Error{code: :unavailable}}; over HTTP and WS it used to be{:ok, %{"failed" => 1}}.publish_batch/2still reports partial refusals as{:ok, %{"failed" => n}}. - Options are checked at start: a missing name, token or host, a wrong scheme, an unknown
transport or parser, an unknown option (with a hint), an option given twice — the client
refuses to start with the reason instead of crash-looping in
connect. Hybridwrites over the same WebSocket when the bus speaks API 1; over HTTP otherwise.Parser.Jsontakes a payload the bus already decoded (WS/HTTP) as is: strings stay strings. It used to re-parse them —"hello"was redelivered forever, a string holding JSON became a map.- An undecodable event is terminated (
term, visible among dropped events in the console) instead of being redelivered forever. - A dynamic subscription (
LogDB.subscribe/2,3) is repeated after every reconnect. - Publishing reads the transport from an ETS table instead of calling the connection process, so it never waits behind incoming events.
- Reconnect backs off (1 s, 2 s, 4 s … 30 s) with jitter.
Fixed
- The consumer's code can no longer bring the client down:
raise,throw,exitor a reply outside the contract go tohandle_error/2; stray messages are ignored. {:ack, state}with a bus that puts the id inack_id(before/v1) used to sendack([nil]).- A half-open WebSocket is detected: three pings without any frame (15–20 s, plus up to 5 s to
close) and the client reconnects.
disconnect/1really closes the socket. - A payload that is not valid UTF-8 no longer crashes the WS socket for everyone or raises over
HTTP — that call gets
{:error, %LogDB.Error{code: :invalid}}. - The token no longer ends up in logs (WS disconnect) or in
inspect. - HTTP single
publishkeepsid:(dedup); HTTPconnectchecks the bus and the token. - A transport that exits mid-call gives
{:error, …}instead of an exit in the caller.
Removed
LogDB.Client.ConnectionConfigandLogDB.Client.Options(replaced byLogDB.Client.ConfigandLogDB.Client.ConnectionString).
Upgrading from 0.2
- Match
{:error, _}as before; inside it is now%LogDB.Error{}. Don't match%Req.Response{}or{status, body}. - An app that passes options the client doesn't know will not start; move your own data to
init_arg:(read it ininit/1asopts[:init_arg]). catch :exitaroundLogDB.*calls is no longer needed.- Tests that fake the client by registering
<name>_connand answering:get_transportmust also put{:transport, module, state}into the ETS table<name>_transport. - With a bus without
helloeverything works; Hybrid then writes over HTTP as before.
0.2.11 - 2026-10-08
Fixed
- WebSocket consumers reconnect after the bus closes the socket normally (close code 1000/1001, e.g. a bus restart on deploy); they used to stay disconnected until the service was restarted.
0.2.10 and earlier
See the git history.