MyNixOS website logo
Description

Postgres implementations for eventium.

Eventium-postgresql provides a PostgreSQL-based event store implementation for the Eventium event sourcing framework. It uses the Persistent library for type-safe database access and provides efficient event storage and retrieval with support for aggregate streams, event versioning, and optimistic concurrency control. This is a production-ready backend for event-sourced applications.

Eventium PostgreSQL

PostgreSQL-based event store implementation for production event sourcing systems.

Overview

eventium-postgresql provides a robust, production-ready event store implementation backed by PostgreSQL. It leverages PostgreSQL's ACID guarantees, indexing capabilities, and reliability for persistent event storage with high performance and data integrity.

Features

  • ACID Transactions - Full consistency guarantees
  • Optimistic Concurrency - Prevents lost updates with version checks
  • Efficient Indexing - Fast event retrieval by stream and position
  • Global Event Ordering - Sequence numbers for time-ordered queries
  • Type-Safe Access - Uses Persistent library for database operations
  • Production Ready - Battle-tested PostgreSQL backend
  • Multi-Process Support - Concurrent access from multiple applications

Database Schema

The implementation creates two main tables:

  • Events Table - Stores events with aggregate keys, versions, and payloads
  • Global Events Table - Maintains global ordering with sequence numbers

Indexes ensure fast lookups by:

  • Stream key + version
  • Global sequence number
  • Event types (for projections)

Installation

Add to your package.yaml:

dependencies:
  - eventium-core
  - eventium-sql-common
  - eventium-postgresql
  - persistent-postgresql  # PostgreSQL driver

Usage

import Eventium.Store.Postgresql
import Database.Persist.Postgresql

main :: IO ()
main = do
  let connStr = "host=localhost dbname=eventstore user=postgres"
  
  withPostgresqlPool connStr 10 $ \pool -> do
    -- Initialize schema
    flip runSqlPool pool $ do
      runMigration migrateAll
      
      -- Create event store
      let store = makePostgresqlEventStore pool
      
      -- Use with command handlers
      result <- applyCommandHandler 
        (eventStoreWriter store)
        (eventStoreReader store)
        commandHandler
        aggregateId
        command

Configuration

Connection String

-- Basic connection
"host=localhost port=5432 dbname=mydb user=myuser password=mypass"

-- With connection pool
withPostgresqlPool connectionString poolSize $ \pool -> ...

Connection Pooling

Recommended settings for production:

-- Pool size based on concurrent requests
poolSize = numCores * 2 + effectiveSpindleCount

-- Example: 10 connections for typical web app
withPostgresqlPool connStr 10 $ \pool -> ...

Setup

Start PostgreSQL with Docker

# Using docker-compose (provided in project root)
docker-compose up -d postgres

# Or manually
docker run -d \
  --name eventium-postgres \
  -e POSTGRES_PASSWORD=postgres \
  -e POSTGRES_DB=eventstore \
  -p 5432:5432 \
  postgres:15

Run Migrations

runSqlPool (runMigration migrateAll) pool

Performance

PostgreSQL provides excellent performance characteristics:

  • Writes: ~1000-5000 events/sec (single connection)
  • Reads: ~10000-50000 events/sec (with proper indexing)
  • Scalability: Read replicas for query scaling

See postgres-event-store-bench/ for benchmarking scripts.

Best Practices

  1. Use Connection Pooling - Essential for web applications
  2. Index Strategy - Default indexes cover common queries
  3. Backup Strategy - Regular PostgreSQL backups
  4. Monitoring - Watch connection pool usage and query performance
  5. Read Replicas - Scale read models with PostgreSQL replication

Production Considerations

  • High Availability - Use PostgreSQL replication
  • Backup & Recovery - Point-in-time recovery with WAL archiving
  • Monitoring - Track event growth and query performance
  • Connection Limits - Configure max_connections appropriately

Example: Complete Setup

import Eventium.Store.Postgresql
import Control.Monad.Logger (runStdoutLoggingT)

setupEventStore :: IO ()
setupEventStore = runStdoutLoggingT $ do
  let connStr = "host=localhost dbname=eventstore"
  
  withPostgresqlPool connStr 10 $ \pool -> do
    -- Run migrations
    flip runSqlPool pool $ runMigration migrateAll
    
    -- Event store is ready to use
    liftIO $ putStrLn "Event store initialized"

Documentation

License

MIT - see LICENSE.md.

Metadata

Version

0.1.0

License

Platforms (78)

    Darwin
    FreeBSD
    Genode
    GHCJS
    Linux
    MMIXware
    NetBSD
    none
    OpenBSD
    Redox
    Solaris
    uefi
    WASI
    Windows
Show all
  • aarch64-darwin
  • aarch64-freebsd
  • aarch64-genode
  • aarch64-linux
  • aarch64-netbsd
  • aarch64-none
  • aarch64-uefi
  • aarch64-windows
  • aarch64_be-none
  • arm-none
  • armv5tel-linux
  • armv6l-linux
  • armv6l-netbsd
  • armv6l-none
  • armv7a-linux
  • armv7a-netbsd
  • armv7l-linux
  • armv7l-netbsd
  • avr-none
  • i686-cygwin
  • i686-freebsd
  • i686-genode
  • i686-linux
  • i686-netbsd
  • i686-none
  • i686-openbsd
  • i686-windows
  • javascript-ghcjs
  • loongarch64-linux
  • m68k-linux
  • m68k-netbsd
  • m68k-none
  • microblaze-linux
  • microblaze-none
  • microblazeel-linux
  • microblazeel-none
  • mips-linux
  • mips-none
  • mips64-linux
  • mips64-none
  • mips64el-linux
  • mipsel-linux
  • mipsel-netbsd
  • mmix-mmixware
  • msp430-none
  • or1k-none
  • powerpc-linux
  • powerpc-netbsd
  • powerpc-none
  • powerpc64-linux
  • powerpc64le-linux
  • powerpcle-none
  • riscv32-linux
  • riscv32-netbsd
  • riscv32-none
  • riscv64-linux
  • riscv64-netbsd
  • riscv64-none
  • rx-none
  • s390-linux
  • s390-none
  • s390x-linux
  • s390x-none
  • vc4-none
  • wasm32-wasi
  • wasm64-wasi
  • x86_64-cygwin
  • x86_64-darwin
  • x86_64-freebsd
  • x86_64-genode
  • x86_64-linux
  • x86_64-netbsd
  • x86_64-none
  • x86_64-openbsd
  • x86_64-redox
  • x86_64-solaris
  • x86_64-uefi
  • x86_64-windows