- Load Stream: Fetch all committed event envelopes for a specific Aggregate ID, ordered sequentially by their stream version.
- Append Stream: Append a block of new events to the stream in a single transaction.
Optimistic Concurrency Control (OCC)
When multiple application server instances handle requests for the same aggregate instance simultaneously, they can cause race conditions. If Server A and Server B both load an account at revision5, execute validations, and attempt to append events, they could corrupt the aggregate state if both succeed.
To prevent this, our framework implements Optimistic Concurrency Control:
- When loading an aggregate, the repository tracks its current version (e.g.,
ExpectedRevision::Exact(5)). - When appending events, the database adapter verifies that the current version of the stream in the database is still exactly
5. - If another request edited the stream first and advanced it to
6, the transaction is rolled back and the append fails with a concurrency violation error (RepositoryError::Concurrency).
OCC State Transition Flow
Standard Relational Database Schema
Our SQLite and PostgreSQL adapters share a unified table schema design. It enforces strict sequential versions per aggregate stream while tracking a global sequence sequence for asynchronous projection engines.Configuring Database Adapters
Our framework supports multiple database options depending on your environment.Database Support Matrix
| Database Backend | Feature Flag | Supported Modes | Realtime Support | Production Ready |
|---|---|---|---|---|
| SQLite | "sqlite" | Native Sync (event, checkpoint, idempotency, snapshot, atomic idempotent append) | Yes (via SSE polling/polling stream) | Yes |
| PostgreSQL | "postgres" | Native Sync (event, checkpoint, idempotency, snapshot, atomic idempotent append) | Yes (via SSE polling/polling stream) | Yes |
| LibSQL / Turso | "wasi-libsql" | Async HTTP / Hrana SQL query helpers | Counter app supports SSE polling or Redis wake | Experimental / WASM |
| Redis | "redis" | Async (event, checkpoint, pub/sub) | Yes (via Pub/Sub / SSE notifications) | Experimental / WASM |
| MySQL | "mysql", "wasi-mysql", "spin-mysql" | Native Sync stores plus raw TCP Wasmtime and Spin SDK query helpers | Counter app supports SSE polling or Redis wake | Yes for native stores; runtime helpers are experimental / WASM |
To Enable Durable Database Adapters:
Custom schema table names are validated when constructingSqlSchemaConfig:
- SQLite Support: Enable the
"sqlite"feature. - PostgreSQL Support: Enable the
"postgres"feature. - MySQL Support: Enable the
"mysql"feature. - WASI MySQL Helper: Enable
"wasi-mysql"for raw TCP MySQL query execution from generic Wasmtime/WASI runtimes. - Spin MySQL Helper: Enable
"spin-mysql"for Spin SDK MySQL query execution. - LibSQL Support: Enable the
"wasi-libsql"feature. - Redis Support: Enable the
"redis"feature with"wasi-redis"or"spin-redis".
[!NOTE] We support SQLite, PostgreSQL, MySQL, LibSQL, and Redis backends. The library provides durable stores, checkpoint stores, idempotency stores, and notification primitives. Push-style realtime delivery is application-owned: use polling, SSE, WebSocket, an outbox worker, binlog CDC, Redis, NATS, Kafka, or another fan-out layer as appropriate. Redis pub/sub support is notification-only; durable event replay remains the source of truth.For request idempotency, prefer
Repository::execute_idempotent_atomic with the native SQL event stores. Repository::execute_idempotent remains available for portable and non-strict workloads, but it coordinates a separate idempotency store and is not crash-atomic across both stores.
1. SQLite Store (Embedded File)
Perfect for edge applications, local databases, or desktop apps. Enable with the"sqlite" feature.
2. PostgreSQL Store (Production Microservice)
Designed for high-concurrency production microservices. Enable with the"postgres" feature.
3. Redis Store (Experimental Async)
Redis support is async-only and experimental. Enable"redis" with either
"wasi-redis" for the raw RESP WASI client or "spin-redis" for Spin SDK
Redis. The adapter uses a Lua append script for atomic expected-revision
checks, global sequence allocation, stream revision updates, and event indexes.