# AetherObservatory Guide In this guide we are going to walk through example code to illustrate the usage of the `AetherObservatory::`. When finished you will have a class to create events and a class that subscribes to those events. #### Table of Contents - [Creating Events](#creating-events) - [Creating an Observer and Subscribing to Events](#creating-an-observer-and-subscribing-to-events) - [Sending an Event to your Observer](#sending-an-event-to-your-observer) - [Stopping Observers](#stopping-observers) - [Using Dynamic Event Names](#using-dynamic-event-names) - [Multiple Event Topics](#multiple-event-topics) ## Creating Events To begin create an `ApplicationEvent` class that extends the `AetherObservatory::EventBase` class. Next configure a prefix for event names using `event_prefix`. This is optional, but encouraged to help prevent naming collisions with other domains. Every domain event we define as a sub-class to the `ApplicationEvent` will inherit this prefix. ```ruby module AetherObservatory module Examples class ApplicationEvent < AetherObservatory::EventBase event_prefix 'talkbox' end end end ``` Next we create an event class called `ExampleEvent` that extends our `ApplicationEvent`. In this class we define the topic we would like our event sent to using the `event_name` method. Lastly we will define our data using the `attribute` method. ```ruby module AetherObservatory module Examples class ExampleEvent < AetherObservatory::Examples::ApplicationEvent event_name 'example1' attribute :message attribute :timestamp, default: -> { Time.current } end end end ``` Now we have a class to create new events. Each time you create a new event, it will be sent to each topic you added via the `event_name` method. ```ruby AetherObservatory::Examples::ExampleEvent.create(message: 'hello world') ``` Running the command above will display a log message like you see below. ```irb irb(main):018:0> AetherObservatory::Examples::ExampleEvent.create(message: 'hello world') [AetherObservatory::Examples::ExampleEvent] Create event for topic: [talkbox.example1] => nil irb(main):019:0> ``` Now that we have an `ExampleEvent` class to create events we need to create an observer to listen for those events.
Top
## Creating an Observer and Subscribing to Events Our new event class `ExampleEvent` creates a new event on the `talkbox.example1` topic so this is the topic we need to create a observer for. We start by creating another class called `ExampleObserver` that extends the `AetherObservatory::ObserverBase` class. Next we use the `subscribe_to` method to register this observer to the topic `talkbox.example1`. We also need to define a `process` method that will be called each time your observer receives an event. In this `process` method you have access to `event_payload` and `event_name` objects for your own logic. ```ruby module AetherObservatory module Examples class ExampleObserver < AetherObservatory::ObserverBase subscribe_to 'talkbox.example1' def process puts <<-EVENT ************************************ Event processed: Name: #{event_name.inspect} Message: #{event_payload.message} Timestamp: #{event_payload.timestamp} Event Payload: #{event_payload.inspect} ************************************ EVENT end end end end ``` Now that we have a new observer named `ExampleObserver`, we will need to start our observer before it will process any events. Observers default to `stopped`, so we need to call `start` on each observer before they will recieve events. Inside an initilizer is the recommended location to start your observers. ```ruby AetherObservatory::Examples::ExampleObserver.start ```
Top
## Sending an Event to your Observer Now that you have all your classes created you can send events to your observer via the `create` method. ```ruby AetherObservatory::Examples::ExampleEvent.create(message: 'hello world') ``` Calling create on your `ExampleEvent` class will trigger the `process` method in the `ExampleObserver` class. You should see the following logged output. ```irb irb(main):040:0> AetherObservatory::Examples::ExampleEvent.create(message: 'hello world') ************************************ Event processed: Name: "talkbox.example1" Message: hello world Timestamp: 2024-05-23 15:17:16 UTC Event Payload: ##, @original_attribute=#, @original_attribute=nil>, @value="hello world">, "timestamp"=>#, @name="timestamp", @value_before_type_cast=#, @type=#, @original_attribute=nil, @memoized_value_before_type_cast=Thu, 23 May 2024 15:17:16.082153128 UTC +00:00, @value=Thu, 23 May 2024 15:17:16.082153128 UTC +00:00>}>> ************************************ [AetherObservatory::Examples::ExampleEvent] Create event for topic: [talkbox.example1] => nil ```
Top
## Stopping Observers To stop your observer from processing events you can call the `stop` method on your observer class. This stops only that observer class from processing events. ```ruby AetherObservatory::Examples::ExampleObserver.stop ```
Top
## Using Dynamic Event Names Create a new class called `RandomEvent` that extends `ApplicationEvent`. Then pass a block to the `event_name` method. This allows you to dynamiclly select your topic at the time of event creation. *Note: [ApplicationEvent](#creating-events) class was created at the beginning of this guide.* ```ruby module AetherObservatory module Examples class RandomEvent < AetherObservatory::Examples::ApplicationEvent event_name { select_a_topic_at_random } attribute :message private def select_a_topic_at_random %w(test support customer).sample end end end end ``` You can now create a few events with your new class using the `create` method of that class. ```ruby AetherObservatory::Examples::RandomEvent.create(message: 'hello world') ``` As you can see from the following output a random event name is selected each time you call `create`. ```irb irb(main):078:0> AetherObservatory::Examples::RandomEvent.create(message: 'hello world') [AetherObservatory::Examples::RandomEvent] Create event for topic: [talkbox.support] => nil irb(main):079:0> AetherObservatory::Examples::RandomEvent.create(message: 'hello world') [AetherObservatory::Examples::RandomEvent] Create event for topic: [talkbox.test] => nil irb(main):080:0> AetherObservatory::Examples::RandomEvent.create(message: 'hello world') [AetherObservatory::Examples::RandomEvent] Create event for topic: [talkbox.support] => nil irb(main):081:0> AetherObservatory::Examples::RandomEvent.create(message: 'hello world') [AetherObservatory::Examples::RandomEvent] Create event for topic: [talkbox.customer] => nil ```
Top
## Multiple Event Topics In this example we are going to create an event class that sends events to two different topics based on the `level` attribute from the event class. We are also going to make two observer classes that subscribe to different events based on their role in the system. *Note: [ApplicationEvent](#creating-events) class was created at the beginning of this guide.* We first create the `TalkboxCallQueueEvent` class. This class will send each event to the `talkbox.call_queues.events.all` topic and to the `level` scoped topic. ```ruby module AetherObservatory module Examples class TalkboxCallQueueEvent < AetherObservatory::Examples::ApplicationEvent event_name 'call_queues.events.all' event_name { "call_queues.events.#{level}" } attribute :level, default: 'info' end end end ``` The new `TalkboxCallQueueEvent` class will send all events to the `all` topic. However the events will also be sent to their specific event `level` scoped topic. This allows us to have one observer logging call history and a second observer that handles events with the scoped `level` or error for topic `talkbox.call_queues.events.error`. Next we need to create a new class called `TalkboxCallHistoryObserver`. This observer will subscribe to the `talkbox.call_queues.events.all` topic. This classes function is to record all call queue events. ```ruby module AetherObservatory module Examples class TalkboxCallHistoryObserver < AetherObservatory::ObserverBase subscribe_to 'talkbox.call_queues.events.all' delegate :level, to: :event_payload def process puts <<-EVENT ************************************ Event processed: Name: #{event_name.inspect} Level: #{event_payload.level} Event Payload: #{event_payload.inspect} ************************************ EVENT end end end end ``` Next we need a class called `TalkboxCallErrorObserver`. This class only subscribes to the `talkbox.call_queues.events.error` topic. It only cares about `error` level events and nothing else. ```ruby module AetherObservatory module Examples class TalkboxCallErrorObserver < AetherObservatory::ObserverBase subscribe_to 'talkbox.call_queues.events.error' def process puts <<-EVENT ************************************ Error Event processed: Name: #{event_name.inspect} Level: #{event_payload.level} Event Payload: #{event_payload.inspect} ************************************ EVENT end end end end ``` We need to be sure to start our new observers before they will recieve any events. ```ruby AetherObservatory::Examples::TalkboxCallHistoryObserver.start AetherObservatory::Examples::TalkboxCallErrorObserver.start ``` Finally we are ready to create a new event and see what happens. First we create an event with a default level. ```ruby AetherObservatory::Examples::TalkboxCallQueueEvent.create ``` Running the create with no parameters will have a default level of `info`. You will see the following output. ```irb irb(main):058:0> AetherObservatory::Examples::TalkboxCallQueueEvent.create ************************************ Event processed: Name: "talkbox.call_queues.events.all" Level: info Event Payload: ##, @original_attribute=nil, @value="info">}>> ************************************ [AetherObservatory::Examples::TalkboxCallQueueEvent] Create event for topic: [talkbox.call_queues.events.all] [AetherObservatory::Examples::TalkboxCallQueueEvent] Create event for topic: [talkbox.call_queues.events.info] => nil ``` Next we will try creating a new event but this time we set the `level` to `error`. ```ruby AetherObservatory::Examples::TalkboxCallQueueEvent.create(level: 'error') ``` As you can see from the output, setting the `level` to `error` will send an event to both classes. ```irb irb(main):059:0> AetherObservatory::Examples::TalkboxCallQueueEvent.create(level: 'error') ************************************ Event processed: Name: "talkbox.call_queues.events.all" Level: error Event Payload: ##, @original_attribute=#, @original_attribute=nil>, @value="error">}>> ************************************ [AetherObservatory::Examples::TalkboxCallQueueEvent] Create event for topic: [talkbox.call_queues.events.all] ************************************ Error Event processed: Name: "talkbox.call_queues.events.error" Level: error Event Payload: ##, @original_attribute=#, @original_attribute=nil>, @value="error">}>> ************************************ [AetherObservatory::Examples::TalkboxCallQueueEvent] Create event for topic: [talkbox.call_queues.events.error] => nil ```
Top