All Projects → commanded → Eventstore

commanded / Eventstore

Licence: mit
Event store using PostgreSQL for persistence

Programming Languages

elixir
2628 projects

Projects that are alternatives of or similar to Eventstore

Eventstore
The stream database optimised for event sourcing
Stars: ✭ 4,395 (+502.88%)
Mutual labels:  event-sourcing, eventstore, database, cqrs
Commanded
Use Commanded to build Elixir CQRS/ES applications
Stars: ✭ 1,280 (+75.58%)
Mutual labels:  event-sourcing, eventstore, cqrs-es, cqrs
flighthub
Flight ticket booking system implemented with CQRS and ES.
Stars: ✭ 26 (-96.43%)
Mutual labels:  cqrs, event-sourcing, cqrs-es
les
Go directly from an event storming to a working API: Event Markdown / Markup validation & NodeJS CQRS/ES application builder.
Stars: ✭ 48 (-93.42%)
Mutual labels:  cqrs, eventstore, cqrs-es
node-cqrs
CQRS backbone with event sourcing for Node.js
Stars: ✭ 63 (-91.36%)
Mutual labels:  cqrs, eventstore, event-sourcing
node-event-storage
An optimized event store for node.js
Stars: ✭ 29 (-96.02%)
Mutual labels:  cqrs, eventstore, event-sourcing
eventuous
Minimalistic Event Sourcing library for .NET
Stars: ✭ 236 (-67.63%)
Mutual labels:  cqrs, eventstore, event-sourcing
iam-ddd-cqrs-es-nestjs
Identity and Access Management
Stars: ✭ 34 (-95.34%)
Mutual labels:  cqrs, eventstore, event-sourcing
wolkenkit-eventstore
wolkenkit-eventstore is an open-source eventstore for Node.js that is used by wolkenkit.
Stars: ✭ 79 (-89.16%)
Mutual labels:  cqrs, eventstore, event-sourcing
Eventually Rs
Event Sourcing for Rust
Stars: ✭ 277 (-62%)
Mutual labels:  event-sourcing, eventstore, cqrs
Event Sourcing Cqrs Examples
Event Sourcing and CQRS in practice.
Stars: ✭ 265 (-63.65%)
Mutual labels:  event-sourcing, cqrs-es, cqrs
Sqlstreamstore
Stream Store library targeting RDBMS based implementations for .NET
Stars: ✭ 374 (-48.7%)
Mutual labels:  event-sourcing, postgresql, cqrs
Learning.EventStore
A framework for CQRS, Eventsourcing, and messaging that uses Redis pub/sub for messaging and offers event persistence in Redis, SQL Server, or PostgreSQL.
Stars: ✭ 58 (-92.04%)
Mutual labels:  cqrs, eventstore, event-sourcing
go-eventually
Idiomatic Event Sourcing in Go
Stars: ✭ 76 (-89.57%)
Mutual labels:  cqrs, event-sourcing, cqrs-es
VehicleTracker
Vehicle Tracker with Microservice example
Stars: ✭ 70 (-90.4%)
Mutual labels:  cqrs, event-sourcing, cqrs-es
akka-persistence-foundationdb
A replicated Akka Persistence journal backed by FoundationDB
Stars: ✭ 43 (-94.1%)
Mutual labels:  cqrs, event-sourcing, cqrs-es
delta
DDD-centric event-sourcing library for the JVM
Stars: ✭ 15 (-97.94%)
Mutual labels:  cqrs, event-sourcing, cqrs-es
workflow
Functional CQRS Eventsourcing Engine
Stars: ✭ 22 (-96.98%)
Mutual labels:  cqrs, eventstore, event-sourcing
fee-office
A DDD, CQRS, ES demo application
Stars: ✭ 35 (-95.2%)
Mutual labels:  cqrs, event-sourcing, cqrs-es
zio-event-sourcing
Purely functional concurent and scalable persistance layer implementing CQRS
Stars: ✭ 34 (-95.34%)
Mutual labels:  cqrs, event-sourcing, cqrs-es

EventStore

Event store implemented in Elixir. Uses PostgreSQL as the underlying storage engine.

Requires Elixir v1.6 and PostgreSQL v9.5 or newer.

EventStore supports running on a cluster of nodes.

MIT License

Build Status


Overview

This README and the following guides follow the master branch which may not be the currently published version. Read docs for the latest published version of EventStore on Hex.


Example usage

Define an event store module:

defmodule MyEventStore do
  use EventStore, otp_app: :my_app
end

Start the event store:

{:ok, _pid} = MyEventStore.start_link()

Create one or more event structs to be persisted (serialized to JSON by default):

defmodule ExampleEvent do
  defstruct [:key]
end

Append events to a stream:

stream_uuid = UUID.uuid4()
expected_version = 0

events = [
  %EventStore.EventData{
    event_type: "Elixir.ExampleEvent",
    data: %ExampleEvent{key: "value"},
    metadata: %{user: "[email protected]"}
  }
]

:ok = MyEventStore.append_to_stream(stream_uuid, expected_version, events)

Read all events from a single stream, starting at the stream's first event:

{:ok, events} = MyEventStore.read_stream_forward(stream_uuid)

More: Usage guide

Subscribe to events appended to all streams:

{:ok, subscription} = MyEventStore.subscribe_to_all_streams("example_subscription", self())

# Wait for the subscription confirmation
receive do
  {:subscribed, ^subscription} ->
    IO.puts("Successfully subscribed to all streams")
end

# Receive a batch of events appended to the event store
receive do
  {:events, events} ->
    IO.puts("Received events: #{inspect events}")

    # Acknowledge successful receipt of events
    :ok = MyEventStore.ack(subscription, events)
end

In production use you would use a GenServer subscriber process and the handle_info/2 callback to receive events.

More: Subscriptions guide

Used in production?

Yes, this event store is being used in production.

PostgreSQL is used for the underlying storage. Providing guarantees to store data securely. It is ACID-compliant and transactional. PostgreSQL has a proven architecture. A strong reputation for reliability, data integrity, and correctness.

Backup and administration

You can use any standard PostgreSQL tool to manage the event store data:

Benchmarking performance

Run the benchmark suite using mix with the bench environment, as configured in config/bench.exs. Logging is disabled for benchmarking.

MIX_ENV=bench mix do es.reset, app.start, bench

Example output:

## AppendEventsBench
benchmark name                         iterations   average time
append events, single writer                  100   20288.68 µs/op
append events, 10 concurrent writers           10   127416.90 µs/op
append events, 20 concurrent writers            5   376836.60 µs/op
append events, 50 concurrent writers            2   582350.50 µs/op
## ReadEventsBench
benchmark name                         iterations   average time
read events, single reader                    500   3674.93 µs/op
read events, 10 concurrent readers             50   44653.98 µs/op
read events, 20 concurrent readers             20   73927.55 µs/op
read events, 50 concurrent readers             10   188244.80 µs/op
## SubscribeToStreamBench
benchmark name                         iterations   average time
subscribe to stream, 1 subscription           100   27687.97 µs/op
subscribe to stream, 10 subscriptions          50   56047.72 µs/op
subscribe to stream, 20 subscriptions          10   194164.40 µs/op
subscribe to stream, 50 subscriptions           5   320435.40 µs/op

After running two benchmarks you can compare the runs:

MIX_ENV=bench mix bench.cmp -d percent

You can also produce an HTML page containing a graph comparing benchmark runs:

MIX_ENV=bench mix bench.graph

Taking the above example output, the append events benchmark is for writing 100 events in a single batch. That's what the µs/op average time is measuring. For a single writer it takes on average 0.02s per 100 events appended (4,929 events/sec) and for 50 concurrent writers it's 50 x 100 events in 0.58s (8,586 events/sec).

For reading events it takes a single reader 3.67ms to read 100 events (27,211 events/sec) and for 50 concurrent readers it takes 0.19s (26,561 events/sec).

Using the benchmark suite

The purpose of the benchmark suite is to measure the performance impact of proposed changes, as opposed to looking at the raw numbers. The above figures are taken when run against a local PostgreSQL database. You can run the benchmarks against your own hardware to get indicative performance figures for the Event Store.

The benchmark suite is configured to use Erlang's external term format serialization. Using another serialization format, such as JSON, will likely have a negative impact on performance.

Testing

Tests can be run using any Postgres database instance, including via Docker.

To use Docker, first pull the latest Postgres image:

docker pull postgres

A tmpfs mount can be used to run the Docker container with the Postgres data directory stored in memory.

docker run --rm \
  --name postgres \
  --tmpfs=/pgtmpfs \
  -e PGDATA=/pgtmpfs \
  -e POSTGRES_PASSWORD=postgres \
  -e POSTGRES_USER=postgres \
  -p 5432:5432 \
  postgres

Running tests

Create and initialize the test event store databases:

MIX_ENV=test mix event_store.setup

Run the test suite:

mix test

Contributing

Pull requests to contribute new or improved features, and extend documentation are most welcome.

Please follow the existing coding conventions, or refer to the Elixir style guide.

You should include unit tests to cover any changes.

Contributors

EventStore exists thanks to the following people who have contributed.

Need help?

Please open an issue if you encounter a problem, or need assistance.

For commercial support, and consultancy, please contact Ben Smith.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].