tellus
Event-sourced actors

PostgreSQL

Store the device's events and snapshots in PostgreSQL and recover them across processes.

The in-memory store forgets everything when the process ends. For real persistence, the tellus-persistence-postgres crate stores events and snapshots in PostgreSQL. The device stays exactly as in the previous step; only the store changes.

cargo add tellus-persistence-postgres
cargo add sqlx --features runtime-tokio,postgres

Using the PostgreSQL store

tellus-persistence-postgres/examples/tutorials/event_sourced/04_postgres.rs
#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let url = env::var("DATABASE_URL").unwrap_or_else(|_| DATABASE_URL.to_string());
    let pool = PgPool::connect(&url)
        .await
        .context("connection to PostgreSQL")?;
    let store = PostgresStore::new(pool);
    store.migrate().await.context("schema migration")?;

    let persistence = Persistence::new(store.clone()).with_snapshot_store(store);
    let system = ActorSystem::event_sourced(Device, persistence);

    system.root().tell(Command::Record(21.5));
    let readings = system
        .root()
        .ask(Duration::from_secs(5), Command::Read)
        .await
        .context("asking for the readings")?;
    println!("Readings so far: {}", readings.count);

    system.stop();
    system
        .terminated()
        .await
        .context("awaiting actor system termination")
}

PostgresStore wraps a sqlx connection pool. migrate creates the tables for events and snapshots if they do not exist yet. The same store serves as event store and snapshot store.

Every run of this program records one reading and then asks for the readings. Since the device recovers all earlier readings from the database, the count grows from run to run.

Run it

From a clone of the tellus repository, start PostgreSQL with Docker:

docker compose up -d --wait postgres
cargo run --quiet -p tellus-persistence-postgres --example event_sourced_04_postgres
cargo run --quiet -p tellus-persistence-postgres --example event_sourced_04_postgres
Readings so far: 1
Readings so far: 2

docker compose down -v postgres stops the database and resets the readings.

Where to go from here

You have seen the core of event sourcing in tellus: commands, events, handle and apply, recovery by replay, supervision and snapshots, in memory and in PostgreSQL. The explanation Event sourcing covers the guarantees behind it, and the how-to Unit test an actor shows how to test handle and apply without a store.