reckon_db_subscription_backend behaviour (reckon_db v2.1.4)

View Source

Behaviour for pluggable subscription-state backends.

Subscription checkpoints track WHERE each consumer is in a stream (or global log). They are written frequently — every ack — but are small and not latency-critical. Most storage backends can handle them fine; the behaviour exists so that a backend can choose whether to keep checkpoints in its own store or delegate to the Khepri control plane.

The default implementation (reckon_db_khepri_subscription_backend) stores checkpoints in Khepri. This is the natural fit — subscription state IS a control-plane concern, and Ra consensus on checkpoints is exactly what you want for "don't replay already-acknowledged events on leader failover."

Fast log backends (RocksDB, custom) will typically implement reckon_db_log_backend but NOT this — they defer to the Khepri implementation. Having the behaviour explicit makes the split clean.

Summary

Types

state/0

-type state() :: term().

subscription/0

-type subscription() ::
          #{name := binary(),
            selector := term(),
            checkpoint := non_neg_integer(),
            consumer_pid => pid() | undefined,
            metadata => map()}.

Callbacks

ack/4

-callback ack(state(), Name :: binary(), Selector :: term(), Checkpoint :: non_neg_integer()) ->
                 ok | {error, term()}.

close/1

-callback close(state()) -> ok.

exists/2

-callback exists(state(), Name :: binary()) -> boolean().

get/2

-callback get(state(), Name :: binary()) -> {ok, subscription()} | {error, not_found} | {error, term()}.

init/1

-callback init(Opts :: map()) -> {ok, state()} | {error, term()}.

list/1

-callback list(state()) -> {ok, [subscription()]} | {error, term()}.

remove/3

-callback remove(state(), Selector :: term(), Name :: binary()) -> ok | {error, term()}.

save/4

-callback save(state(), Selector :: term(), Name :: binary(), Data :: map()) -> ok | {error, term()}.