Packages
x3m_system
0.9.1
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.1"}
]
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:
```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
```
Register the services (typically from your application's `start/2`) and dispatch a
message to the service by name:
```elixir
:ok = MyApp.Router.register_services()
: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.
## 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`.
## License
Released under the MIT License. See the [LICENSE](https://github.com/x3m-ex/system/blob/master/LICENSE) file.