Packages
x3m_system
0.9.2
0.9.3
0.9.2
0.9.1
0.9.0
0.8.6
0.8.5
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
retired
0.7.20
0.7.19
0.7.18
0.7.17
0.7.16
0.7.15
0.7.14
0.7.13
0.7.12
0.7.11
0.7.10
0.7.9
0.7.8
retired
0.7.7
0.7.6
retired
0.7.5
0.7.4
retired
0.7.3
retired
0.7.2
0.7.1
0.7.0
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
retired
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.9
0.4.8
0.4.7
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.1.1
0.1.0
Building blocks for distributed and/or CQRS/ES systems
Current section
Files
Jump to
Current section
Files
x3m_system
README.md
README.md
# X3m.System
[](https://github.com/x3m-ex/system/actions/workflows/bless.yml)
[](https://hex.pm/packages/x3m_system)
[](https://coveralls.io/github/x3m-ex/system)
Building blocks for distributed and/or CQRS/ES systems in Elixir.
`X3m.System` gives you a small set of composable pieces for building message-driven
backends: a **message** that carries a request and its response, a **router** that
registers services across a cluster, a **dispatcher** that finds a node offering a
service and waits for the reply, and — when you need it — **aggregates** with event
sourcing and a backend-agnostic **scheduler** for delivering messages in the future.
The pieces are **à la carte**. You can use the messaging layer (message + router +
dispatcher) on its own, add aggregates and event sourcing only where you need them,
and use the scheduler independently of everything else.
## Installation
```elixir
def deps do
[
{:x3m_system, "~> 0.9.2"}
]
end
```
One dependency is optional:
- `:elixir_uuid` — needed when working with aggregates (id generation).
## A minimal example
Define a router that registers a service and the module that handles it,
and register the services (typically from your application's `start/2`).
```elixir
defmodule MyApp.Router do
use X3m.System.Router
service :greet, MyApp.Greeter
def authorize(_message), do: :ok
end
defmodule MyApp.Greeter do
alias X3m.System.Message
def greet(%Message{} = message) do
name = message.raw_request["name"]
{:reply, Message.ok(message, "Hello, #{name}!")}
end
end
:ok = MyApp.Router.register_services()
```
Dispatch a message to the service by name:
```elixir
:greet
|> X3m.System.Message.new(raw_request: %{"name" => "Ada"})
|> X3m.System.Dispatcher.dispatch()
#=> %X3m.System.Message{response: {:ok, "Hello, Ada!"}, ...}
```
```mermaid
flowchart LR
C[Caller] -->|"Message.new(:greet)"| D[Dispatcher.dispatch]
D -->|find a node offering :greet| R[Router]
R -->|"authorize/1"| A{authorized?}
A -->|no| F["response: {:error, :forbidden}"]
A -->|yes| H["Greeter.greet/1"]
H -->|"{:reply, Message.ok(...)}"| C
```
No aggregates or event store are involved here — any module registered through a
router can be a dispatch target.
## Dispatch accross the cluster
If you want to try dispatch accross the cluster, run 2 iex sessions:
```bash
iex --sname x3m_1@localhost -S mix
```
and from the other terminal
```bash
iex --sname x3m_2@localhost -S mix
```
Define your router and message handler (Greeter here) and register your services in first iex session (like in example from above),
and then from the second one, connect to the first node:
```elixir
Node.connect :"x3m_1@localhost"
#=> true
```
... and then dispatch message the same way you did in previous example. Result will be the same.
## Guides
- [Getting started](guides/getting-started.md) — install, optional deps, your first dispatch.
- [Messaging](guides/messaging.md) — `Message`, `Router`, `Dispatcher` and the response shapes.
- [Aggregates & event sourcing](guides/aggregates-and-event-sourcing.md) — `Aggregate`, `MessageHandler`, persisting events, snapshotting and supervision.
- [Distribution](guides/distribution.md) — service discovery across nodes, choosing the node, and forwarding.
- [Scheduling](guides/scheduling.md) — persistable, future-dated message delivery with `Scheduler`.
- [Telemetry](guides/telemetry.md) — the emitted events, their measurements, metadata and units.
## Example
The [Banking example](https://github.com/x3m-ex/system/tree/main/examples/bank) is a complete poncho project demonstrating the
full CQRS/ES flow — HTTP API, command aggregates, event store, listener-driven read
model, and cross-node dispatch. See its README for setup and curl walkthrough.
## License
Released under the MIT License. See the [LICENSE](https://github.com/x3m-ex/system/blob/main/LICENSE) file.