Pixelex.Store behaviour (Pixelex v0.1.0)

Copy Markdown View Source

Where events go.

Two adapters ship: Pixelex.Store.Postgres (the real one) and Pixelex.Store.ETS (tests, and a dev server that should not need a database to boot). ClickHouse via ecto_ch and DuckDB via duckdbex fit this behaviour without changes to anything above it, but neither is written — columnar storage earns its operational cost somewhere past the point where partitioned Postgres stops coping, and most apps never get there.

The contract

insert_events/1 receives a batch and must be idempotent on event.id. The ingest buffer may replay a batch after a transient failure, and every event carries a UUIDv7 assigned once at creation, so a replay is a duplicate key rather than a duplicate row.

Summary

Callbacks

Processes the adapter needs running, if any.

Write a batch. Must be idempotent on event.id.

Create whatever the adapter needs. Called by mix pixelex.setup; a no-op for stateless adapters.

Functions

Child specs for the configured adapter, or [] when it needs none.

Write a batch through the configured adapter.

Callbacks

children()

(optional)
@callback children() :: [Supervisor.child_spec() | {module(), term()} | module()]

Processes the adapter needs running, if any.

insert_events(list)

@callback insert_events([Pixelex.Event.t()]) ::
  {:ok, non_neg_integer()} | {:error, term()}

Write a batch. Must be idempotent on event.id.

Returns the number of rows actually written — which is less than the batch size when a replay collided with rows already stored, and that is success, not failure.

setup()

(optional)
@callback setup() :: :ok | {:error, term()}

Create whatever the adapter needs. Called by mix pixelex.setup; a no-op for stateless adapters.

Functions

children()

@spec children() :: list()

Child specs for the configured adapter, or [] when it needs none.

insert_events(events)

@spec insert_events([Pixelex.Event.t()]) ::
  {:ok, non_neg_integer()} | {:error, term()}

Write a batch through the configured adapter.