Events

An event is a message emitted by the system when "something" happens. Again this could be a technical task being completed such as a DatabaseBackedUp, LoadBalancerScaledOut or as a result of changes in your business CreditCardCharged, UserRegistered, PackageShipped.

Use natural language in the past-tense when naming an event since it represents a historic fact has taken place. This also helps improve the readability of your code, as the history of your application can be discussed in terms of the order of events.

Creating an Event

Events are class definitions that extend from Event, eg:

import { Event } from '@node-ts/bus-messages'

export class CreditCardCharged extends Event {
  /**
   * A unique name that identifies the message. This should be done in namespace style syntax,
   * ie: organisation/domain/event-name
   */
  $name = 'my-app/accounts/credit-card-charged'

  /**
   * The contract version of this message. This can be incremented if this message changes the
   * number of properties etc to maintain backwards compatibility
   */
  $version = 1

  /**
   * A credit card was successfully charged
   * @param creditCardToken Identifies the card that was charged
   * @param amount The amount, in USD, that the card was charged for
   */
  constructor (
    readonly creditCardToken: string,
    readonly amount: number
  ) {
  }
}

It's useful to declare all of your messages in a central package that can be shared amongst your publisher and subscriber services.

Publishing an Event

Events can have 0-to-many different subscribers, who are generally interested in performing a next action as a result of the event being raised.

Use .publish() to publish an event:

const creditCardCharged = new CreditCardCharged('abc', 123)

// Publish a message. All subscribers will receive a copy
await bus.publish(creditCardCharged)

// Publish a message along with a set of attributes
await bus.publish(
  creditCardCharged,
  { correlationId: 'tok-1adsfas-df1' }
)

Handling an Event

Events get processed by a Handler. This is a function or a class function that receives the message as a parameter and performs an operation. When the handler returns the message is deleted from the queue.

Implementing a function based handler

import { handlerFor } from '@node-ts/bus-core'

// Function based handler
const creditCardChargedHandler = handlerFor(
  CreditCardCharged,
  async (event: CreditCardCharged) => {
    // ...
  }
)

Implementing a class based handler

import { Handler } from '@node-ts/bus-core'

// Class based handler
class CreditCardChargedHandler implements Handler<CreditCardCharged> {
  messageType = CreditCardCharged
  
  async handle (event: CreditCardCharged) {
    // ...
  }
}

Register the handler with the bus configuration

  const bus = await Bus.configure()
    .withHandler(chargeCreditCardHandler) // Function based handler
    .withHandler(ChargeCreditCardHandler) // Class function based handler
    .initialize()

Remember to .start() the bus to start handling messages

await bus.start()

Last updated