Read Models

August 5, 2026 ยท View on GitHub

Read models are shared Chronicle concepts. Querying, snapshots, watching, and consistency are documented in the shared Chronicle section.

Watching for live changes

Chronicle.ReadModels.watch/2 subscribes the calling process to live changesets for a read model over the kernel's server-streaming Watch RPC. Elixir has no IObservable/ async-iterable equivalent to the C# and TypeScript clients' Watch<TReadModel>(), so this follows the same message-based idiom as Chronicle.Connections.Lifecycle.subscribe/1.

{:ok, watcher} = Chronicle.ReadModels.watch(MyApp.ReadModels.AccountInfo)

receive do
  {:chronicle_read_model_changed, MyApp.ReadModels.AccountInfo, changeset} ->
    # changeset is a %Chronicle.ReadModels.Changeset{} with :model_key, :read_model,
    # :change_type (:added | :modified | :removed), :event_sequence_number, and more.
    IO.inspect(changeset.read_model)

  {:chronicle_read_model_watch_error, MyApp.ReadModels.AccountInfo, reason} ->
    # The stream failed and the watch has ended โ€” call watch/2 again to resume.
    IO.inspect(reason)
end

Chronicle.ReadModels.unwatch(watcher)

Dehydrating a session

A read-model session (created implicitly whenever you read with a :session_id) normally expires on its own. dehydrate_session/4 explicitly cleans one up once the caller is done with it, releasing the resources Chronicle held for it right away.

:ok =
  Chronicle.ReadModels.dehydrate_session(
    MyApp.ReadModels.AccountInfo,
    account_id,
    session_id
  )