View Source Solvent (solvent v0.3.0)
Solvent is an event bus built to be fast and easy-to-use, and takes a lot of inspiration from the CloudEvents spec for the best interoperability with other event systems.
In the CloudEvents specification, every event is required to have an ID, a source, and a type.
The source
field identifies the system that sent the event, and the ID must identify the event and be unique in the scope of the source.
Lastly, the type
field, also called a "topic," identifies the kind of event that took place.
In Solvent, only the type
field is required, but it is strongly recommended to provide a source
field as well.
Solvent generates a version 7 UUID for event ID fields and this rarely needs to be overridden.
See the Solvent.Event
docs for details on what defaults are provided.
Subscribe to the event stream with subscribe/2
, and publish events using publish/2
.
You can also create a Solvent.Subscription
or a Solvent.Event
yourself and pass those to subscribe/1
and publish/1
, respectively.
The functions here share a signature with their corresponding struct functions, but have the additional benefit of interacting with the event bus.
telemetry
Telemetry
[:solvent, :event, :published]
- Description: Emitted when an event is published
- Measurements:
%{}
- Metadata:
%{event_source: String.t(), event_id: String.t(), event_type: String.t(), subscriber_count: non_neg_integer()}
[:solvent, :subscriber, :processing, :start]
- Description: Emitted when a subscriber begins processing an event
- Measurements:
%{}
- Metadata:
%{subscriber_id: String.t(), event_source: String.t(), event_id: String.t(), event_type: String.t()}
[:solvent, :subscriber, :processing, :stop]
- Description: Emitted when a subscriber finishes processing an event
- Measurements:
%{duration: non_neg_integer()}
- Metadata:
%{subscriber_id: String.t(), event_source: String.t(), event_id: String.t(), event_type: String.t()}
[:solvent, :subscriber, :subscribing, :start]
- Description: Emitted when a subscriber begins subscribing to the event stream
- Measurements:
%{}
- Metadata:
%{subscriber_id: String.t(), filter: String.t()}
[:solvent, :subscriber, :subscribing, :stop]
- Description: Emitted when a subscriber is finished subscribing to the event stream
- Measurements:
%{duration: non_neg_integer()}
- Metadata:
%{subscriber_id: String.t(), filter: String.t()}
Link to this section Summary
Functions
Publish an event to the event bus, triggering all subscriber functions.
Subscribe to the event stream with a pre-made Solvent.Subscription
struct.
Subscribe to the event stream.
Remove a subscriber.
Link to this section Functions
Publish an event to the event bus, triggering all subscriber functions.
Only a type (AKA "topic") is required. All other fields can be supplied using the options.
See Solvent.Event
for details on what that struct contains.
All values given as options are inserted into the event struct.
ID values are version 7 UUIDs by default, and you don't need to provide them.
I would recommend using the CloudEvents format for your event's type
field, which starts with a reversed DNS name, and is dot-separated.
This will help avoid collisions with events from other applications.
Solvent.publish("io.github.cantido.myevent.published")
{:ok, "0b06bdb7-06a7-4df9-a825-1fd225ceea43"}
It is also recommended to provide a source
option to identify your application, especially if your subscription did not specify a source
.
Otherwise, all events will be published with a default source, and subscriptions will be triggered for every event traveling through Solvent (including events from other applications).
A good source
value is either a fully-qualified domain name, or a UUID in URN format.
iex> Solvent.publish(
...> "io.github.cantido.documentation.read",
...> id: "read-docs-id",
...> source: "myapp"
...> )
{:ok, {"myapp", "read-docs-id"}}
You can also build an event yourself with Solvent.Event.new/1
and publish it with this function.
Subscribe to the event stream with a pre-made Solvent.Subscription
struct.
Subscribe to the event stream.
The sink is what receives your events, and can be anything that implements the Solvent.Sink
protocol,
which includes anonymous functions, module-function-args tuples, and PIDs.
Here's an example with a module-function-args tuple that subscribes to a single event type
and identifies the subscription as "My first subscriber"
.
iex> Solvent.subscribe(
...> {Solvent.MessengerHandler, :handle_event, []},
...> types: ["com.example.event.published"],
...> id: "My first subscriber"
...> )
{:ok, "My first subscriber"}
This function shares its signature with Solvent.Subscription.new/2
,
and creates a Solvent.Subscription
in the same way,
while also inserting the subscription into the Solvent.SubscriberStore
so that the sink will begin to receive events.
Sinks are given an event identifier, and not the event itself.
Your sink must fetch the full event from the Solvent.EventStore
, so that extra data is not copied between processes.
You must also call Solvent.EventStore.ack/2
once you are done with the event,
unless you want the event to stay in the event store forever.
Tip
Use the
Solvent.Subscriber
module to make a subscriber that automatically acknowledges events, along with lots of other nice features.
You can also create a Solvent.Subscription
struct yourself, and pass it to subscribe/1
.
Remove a subscriber.