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

Link to this function

publish(event, opts \\ [])

View Source

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.

Link to this function

subscribe(sink, opts \\ [])

View Source

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.