1. Technologies
  2. Heimdall

Technologies

Heimdall

A global event bus system

Overview

Heimdall allows you to :

  1. Register for a known event
  2. Emit an event

With these two basic operations, you can use a global event bus to communicate between different parts of your application or other applications.
The Heimdall Global Event bus is a separate system to Stubber and is intended to be a general global event bus for all systems.

Example

A simple example of how Heimdall can be used is to have a financial system emit an event when a transaction is completed.
The event could be emitted with a path like stubbergroup.internal.system.financial.transactions.type.credit.reference.1234.
A reporting system could then listen for events with a path like stubbergroup.internal.system.financial.transactions.type.credit.reference.* and then receive all events for credit transactions.
The reporting system could then process the event and update a report with the new transaction.
If the reporting system wants to receive all events for all transactions it could listen for events with a path like stubbergroup.internal.system.financial.transactions.type.* and then receive all events for all transactions.
This shows how Heimdall Paths can be used to filter events and only receive the events that are relevant to the system.
Another system might be interested in the transactions with reference 1234 and listen for events with a path like stubbergroup.internal.system.financial.transactions.type.#.reference.1234 and then receive only the events for the transaction with reference 1234.

We can see from the above examples that you can use * and # as wildcards in the path to filter events.
* is used to match any value deeper in the path
# is used to match any value at a specific level of the path.

Heimdall Path

A Heimdall path is a string that represents a unique location in the Heimdall event bus. It is used to register for events and emit events.
The path is a string that :

  • contains only alphanumeric characters, hyphens, and underscores
  • starts with an alphanumeric character
  • is case-insensitive
  • uses "." as a separator for different parts of the path

Path Hierarchy

It is very important to have a lot of hierarchy in your path.
Hierarchy is achieved by separating the path into different levels using the "." separator.
Most events need to start with 2 levels of hierarchy for the organization that owns the event. Example : stubbergroup.internal
The path should contain at least 5 levels of hierarchy. Example : stubbergroup.internal.subsystem.component.key.value.key2.value2

Good practices for path hierarchy :

  • The first level should be the organization name
  • Using at least 5 levels of hierarchy
  • Alternating the path levels between keys and values eg. stubbergroup.internal.system.financial.transactions.type.credit.reference.1234

Having a good hierarchy and added some important keys and values into the path allow systems that listen for events to filter on a large number of events and only listen for the ones that are relevant to them.

Heimdall Mechanisms

Heimdall mechanisms are used to control who receives an event.
When registering for an event you specify which mechanism you'd like to use.
Then all listeners using the same mechanism will receive the event according to the rules of the mechanism.
The default mechanism is evt which simply allows all listeners to receive the event.

Mechanisms are a powerful way to control who receives an event.

Here are the available mechanisms :

Mechanism Name Description
evt Event Allows all listeners to receive the event
cbh Call Back Handler Only the last to register will receive the event, guarantees only a single listener will handle the event, also respects the most specific path, so only the most specific path registered AND being the last to register will receive the event
rra Round Robin Approach The event is sent to each listener in turn, starting with the first listener to register, then the second, and so on, until all listeners have received the event, then it starts again with the first listener
rnd Random The event is sent to a random listener, this is useful for load balancing
evb Event Back Used to pass back events to the emitter, this is useful for request/response type events, no partial matching happens on this mechanism, path usually contains a UUID

Registering for an event

To register for an event inside Stubber you use the Heimdall Register task.
When registering for an event you typically specify the following :

  • A UUID so that you can deregister later if you want to stop receiving events
  • The path of the event you want to listen for
  • The heimdall mechanism to use (evt is the default)
  • If the event should be kept or only triggered once
  • How to trigger the event (Stub, action, data to pass etc)

When providing the path to register on you can filter the events you want to receive by using * and # as wildcards in the path.
* is used to match any value deeper in the path
# is used to match any value at a specific level of the path.

eg. stubbergroup.internal.system.financial.transactions.type.#.reference.* will receive all events for any type of transaction with any reference. it would be possible to receive events for stubbergroup.internal.system.financial.transactions.type.credit.reference.1234 and stubbergroup.internal.system.financial.transactions.type.debit.reference.5678 but would not match on events without a reference like stubbergroup.internal.system.financial.transactions.type.credit.
To match on all events for a type of transaction you would use stubbergroup.internal.system.financial.transactions.type.*.

Emitting an event

To emit an event inside Stubber you use the Heimdall Emit task.
When emitting an event you typically specify the following :

  • The path of the event you want to emit
  • The heimdall mechanisms to allow (* is the default allowing all mechanisms to be used)
  • The data payload to send with the event

Advanced Emitting

You can emit on multiple paths at the same time.
This allows you to emit at different levels of the path hierarchy.
Example : stubbergroup.internal.system.financial.transactions.type.credit.reference.1234 and stubbergroup.internal.system.general.references.1234 This would allow systems to find general events across all systems that mention the reference 1234.
So the financial system would emit on stubbergroup.internal.system.general.references.1234 for each transaction reference and the support system might emit on stubbergroup.internal.system.general.references.1234 for each support reference, and then the reporting system could listen for events on stubbergroup.internal.system.general.references.1234 and receive both events.

Emitting on multiple paths is encouraged to allow systems to filter by different hierarchies of the path.

Triggering

When an event is received by the central Heimdall server it is then evaluated to see which listeners should be triggered.

Heimdall will first find all the listeners that match the path or partial path of the event.
It will find the listeners according to the mechanism of the registration. So for the most basic mechanism evt it will find all listeners that match the path or a wildcard path.
For the cbh mechanism it will only find the last listener that matches the most specific path.

Once a list of listeners is found it will then trigger the listeners according to the way that the listener specified in the registration.

An example is shown here : Heimdall Register task