aether_observatory 0.0.1pre4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rubocop.yml +17 -0
- data/Appraisals +17 -0
- data/Gemfile +7 -0
- data/Rakefile +26 -0
- data/aether_observatory.gemspec +44 -0
- data/doc/dependency_decisions.yml +3 -0
- data/docs/CHANGELOG.md +3 -0
- data/docs/README.md +368 -0
- data/gemfiles/rails_6_0.gemfile +8 -0
- data/gemfiles/rails_6_0.gemfile.lock +276 -0
- data/gemfiles/rails_6_1.gemfile +8 -0
- data/gemfiles/rails_6_1.gemfile.lock +279 -0
- data/gemfiles/rails_7_0.gemfile +8 -0
- data/gemfiles/rails_7_0.gemfile.lock +278 -0
- data/gemfiles/rails_7_1.gemfile +8 -0
- data/gemfiles/rails_7_1.gemfile.lock +314 -0
- data/lib/aether_observatory/README.md +318 -0
- data/lib/aether_observatory/configuration.rb +11 -0
- data/lib/aether_observatory/event_base.rb +66 -0
- data/lib/aether_observatory/observer_base.rb +106 -0
- data/lib/aether_observatory/version.rb +5 -0
- data/lib/aether_observatory.rb +15 -0
- data/mkdocs.yml +6 -0
- metadata +226 -0
@@ -0,0 +1,318 @@
|
|
1
|
+
# AetherObservatory Guide
|
2
|
+
|
3
|
+
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.
|
4
|
+
|
5
|
+
#### Table of Contents
|
6
|
+
- [Creating Events](#creating-events)
|
7
|
+
- [Creating an Observer and Subscribing to Events](#creating-an-observer-and-subscribing-to-events)
|
8
|
+
- [Sending an Event to your Observer](#sending-an-event-to-your-observer)
|
9
|
+
- [Stopping Observers](#stopping-observers)
|
10
|
+
- [Using Dynamic Event Names](#using-dynamic-event-names)
|
11
|
+
- [Multiple Event Topics](#multiple-event-topics)
|
12
|
+
|
13
|
+
## Creating Events
|
14
|
+
|
15
|
+
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.
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
module AetherObservatory
|
19
|
+
module Examples
|
20
|
+
class ApplicationEvent < AetherObservatory::EventBase
|
21
|
+
event_prefix 'talkbox'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
```
|
26
|
+
|
27
|
+
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.
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
module AetherObservatory
|
31
|
+
module Examples
|
32
|
+
class ExampleEvent < AetherObservatory::Examples::ApplicationEvent
|
33
|
+
event_name 'example1'
|
34
|
+
|
35
|
+
attribute :message
|
36
|
+
attribute :timestamp, default: -> { Time.current }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
```
|
41
|
+
|
42
|
+
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.
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
AetherObservatory::Examples::ExampleEvent.create(message: 'hello world')
|
46
|
+
```
|
47
|
+
|
48
|
+
Running the command above will display a log message like you see below.
|
49
|
+
|
50
|
+
```irb
|
51
|
+
irb(main):018:0> AetherObservatory::Examples::ExampleEvent.create(message: 'hello world')
|
52
|
+
[AetherObservatory::Examples::ExampleEvent] Create event for topic: [talkbox.example1]
|
53
|
+
=> nil
|
54
|
+
irb(main):019:0>
|
55
|
+
```
|
56
|
+
|
57
|
+
Now that we have an `ExampleEvent` class to create events we need to create an observer to listen for those events.
|
58
|
+
|
59
|
+
<div align="right">
|
60
|
+
<a href="#aetherobservatory-guide">Top</a>
|
61
|
+
</div>
|
62
|
+
|
63
|
+
## Creating an Observer and Subscribing to Events
|
64
|
+
|
65
|
+
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.
|
66
|
+
|
67
|
+
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.
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
module AetherObservatory
|
71
|
+
module Examples
|
72
|
+
class ExampleObserver < AetherObservatory::ObserverBase
|
73
|
+
subscribe_to 'talkbox.example1'
|
74
|
+
|
75
|
+
def process
|
76
|
+
puts <<-EVENT
|
77
|
+
************************************
|
78
|
+
Event processed:
|
79
|
+
Name: #{event_name.inspect}
|
80
|
+
Message: #{event_payload.message}
|
81
|
+
Timestamp: #{event_payload.timestamp}
|
82
|
+
Event Payload: #{event_payload.inspect}
|
83
|
+
************************************
|
84
|
+
EVENT
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
```
|
90
|
+
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.
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
AetherObservatory::Examples::ExampleObserver.start
|
94
|
+
```
|
95
|
+
|
96
|
+
<div align="right">
|
97
|
+
<a href="#aetherobservatory-guide">Top</a>
|
98
|
+
</div>
|
99
|
+
|
100
|
+
## Sending an Event to your Observer
|
101
|
+
|
102
|
+
Now that you have all your classes created you can send events to your observer via the `create` method.
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
AetherObservatory::Examples::ExampleEvent.create(message: 'hello world')
|
106
|
+
```
|
107
|
+
|
108
|
+
Calling create on your `ExampleEvent` class will trigger the `process` method in the `ExampleObserver` class. You should see the following logged output.
|
109
|
+
|
110
|
+
```irb
|
111
|
+
irb(main):040:0> AetherObservatory::Examples::ExampleEvent.create(message: 'hello world')
|
112
|
+
************************************
|
113
|
+
Event processed:
|
114
|
+
Name: "talkbox.example1"
|
115
|
+
Message: hello world
|
116
|
+
Timestamp: 2024-05-23 15:17:16 UTC
|
117
|
+
Event Payload: #<AetherObservatory::Examples::ExampleEvent:0x0000aaaadc2b2118 @attributes=#<ActiveModel::AttributeSet:0x0000aaaadc2b1f38 @attributes={"message"=>#<ActiveModel::Attribute::FromUser:0x0000aaaadc2b1fb0 @name="message", @value_before_type_cast="hello world", @type=#<ActiveModel::Type::Value:0x0000aaaadc101d28 @precision=nil, @scale=nil, @limit=nil>, @original_attribute=#<ActiveModel::Attribute::WithCastValue:0x0000aaaadc2b2dc0 @name="message", @value_before_type_cast=nil, @type=#<ActiveModel::Type::Value:0x0000aaaadc101d28 @precision=nil, @scale=nil, @limit=nil>, @original_attribute=nil>, @value="hello world">, "timestamp"=>#<ActiveModel::Attribute::UserProvidedDefault:0x0000aaaadc2b1f60 @user_provided_value=#<Proc:0x0000aaaadc0f3b38 (irb):15 (lambda)>, @name="timestamp", @value_before_type_cast=#<Proc:0x0000aaaadc0f3b38 (irb):15 (lambda)>, @type=#<ActiveModel::Type::Value:0x0000aaaadc0f3ac0 @precision=nil, @scale=nil, @limit=nil>, @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>}>>
|
118
|
+
************************************
|
119
|
+
[AetherObservatory::Examples::ExampleEvent] Create event for topic: [talkbox.example1]
|
120
|
+
=> nil
|
121
|
+
```
|
122
|
+
|
123
|
+
<div align="right">
|
124
|
+
<a href="#aetherobservatory-guide">Top</a>
|
125
|
+
</div>
|
126
|
+
|
127
|
+
## Stopping Observers
|
128
|
+
|
129
|
+
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.
|
130
|
+
|
131
|
+
```ruby
|
132
|
+
AetherObservatory::Examples::ExampleObserver.stop
|
133
|
+
```
|
134
|
+
|
135
|
+
<div align="right">
|
136
|
+
<a href="#aetherobservatory-guide">Top</a>
|
137
|
+
</div>
|
138
|
+
|
139
|
+
## Using Dynamic Event Names
|
140
|
+
|
141
|
+
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.
|
142
|
+
|
143
|
+
<sup>*Note: [ApplicationEvent](#creating-events) class was created at the beginning of this guide.*</sup>
|
144
|
+
|
145
|
+
```ruby
|
146
|
+
module AetherObservatory
|
147
|
+
module Examples
|
148
|
+
class RandomEvent < AetherObservatory::Examples::ApplicationEvent
|
149
|
+
event_name { select_a_topic_at_random }
|
150
|
+
|
151
|
+
attribute :message
|
152
|
+
|
153
|
+
private
|
154
|
+
|
155
|
+
def select_a_topic_at_random
|
156
|
+
%w(test support customer).sample
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
```
|
162
|
+
|
163
|
+
You can now create a few events with your new class using the `create` method of that class.
|
164
|
+
|
165
|
+
```ruby
|
166
|
+
AetherObservatory::Examples::RandomEvent.create(message: 'hello world')
|
167
|
+
```
|
168
|
+
|
169
|
+
As you can see from the following output a random event name is selected each time you call `create`.
|
170
|
+
|
171
|
+
```irb
|
172
|
+
irb(main):078:0> AetherObservatory::Examples::RandomEvent.create(message: 'hello world')
|
173
|
+
[AetherObservatory::Examples::RandomEvent] Create event for topic: [talkbox.support]
|
174
|
+
=> nil
|
175
|
+
irb(main):079:0> AetherObservatory::Examples::RandomEvent.create(message: 'hello world')
|
176
|
+
[AetherObservatory::Examples::RandomEvent] Create event for topic: [talkbox.test]
|
177
|
+
=> nil
|
178
|
+
irb(main):080:0> AetherObservatory::Examples::RandomEvent.create(message: 'hello world')
|
179
|
+
[AetherObservatory::Examples::RandomEvent] Create event for topic: [talkbox.support]
|
180
|
+
=> nil
|
181
|
+
irb(main):081:0> AetherObservatory::Examples::RandomEvent.create(message: 'hello world')
|
182
|
+
[AetherObservatory::Examples::RandomEvent] Create event for topic: [talkbox.customer]
|
183
|
+
=> nil
|
184
|
+
```
|
185
|
+
|
186
|
+
<div align="right">
|
187
|
+
<a href="#aetherobservatory-guide">Top</a>
|
188
|
+
</div>
|
189
|
+
|
190
|
+
## Multiple Event Topics
|
191
|
+
|
192
|
+
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.
|
193
|
+
|
194
|
+
<sup>*Note: [ApplicationEvent](#creating-events) class was created at the beginning of this guide.*</sup>
|
195
|
+
|
196
|
+
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.
|
197
|
+
|
198
|
+
```ruby
|
199
|
+
module AetherObservatory
|
200
|
+
module Examples
|
201
|
+
class TalkboxCallQueueEvent < AetherObservatory::Examples::ApplicationEvent
|
202
|
+
event_name 'call_queues.events.all'
|
203
|
+
event_name { "call_queues.events.#{level}" }
|
204
|
+
|
205
|
+
attribute :level, default: 'info'
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
```
|
210
|
+
|
211
|
+
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`.
|
212
|
+
|
213
|
+
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.
|
214
|
+
|
215
|
+
```ruby
|
216
|
+
module AetherObservatory
|
217
|
+
module Examples
|
218
|
+
class TalkboxCallHistoryObserver < AetherObservatory::ObserverBase
|
219
|
+
subscribe_to 'talkbox.call_queues.events.all'
|
220
|
+
|
221
|
+
delegate :level, to: :event_payload
|
222
|
+
|
223
|
+
def process
|
224
|
+
puts <<-EVENT
|
225
|
+
************************************
|
226
|
+
Event processed:
|
227
|
+
Name: #{event_name.inspect}
|
228
|
+
Level: #{event_payload.level}
|
229
|
+
Event Payload: #{event_payload.inspect}
|
230
|
+
************************************
|
231
|
+
EVENT
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
```
|
237
|
+
|
238
|
+
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.
|
239
|
+
|
240
|
+
```ruby
|
241
|
+
module AetherObservatory
|
242
|
+
module Examples
|
243
|
+
class TalkboxCallErrorObserver < AetherObservatory::ObserverBase
|
244
|
+
subscribe_to 'talkbox.call_queues.events.error'
|
245
|
+
|
246
|
+
def process
|
247
|
+
puts <<-EVENT
|
248
|
+
************************************
|
249
|
+
Error Event processed:
|
250
|
+
Name: #{event_name.inspect}
|
251
|
+
Level: #{event_payload.level}
|
252
|
+
Event Payload: #{event_payload.inspect}
|
253
|
+
************************************
|
254
|
+
EVENT
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
259
|
+
```
|
260
|
+
|
261
|
+
We need to be sure to start our new observers before they will recieve any events.
|
262
|
+
|
263
|
+
```ruby
|
264
|
+
AetherObservatory::Examples::TalkboxCallHistoryObserver.start
|
265
|
+
AetherObservatory::Examples::TalkboxCallErrorObserver.start
|
266
|
+
```
|
267
|
+
|
268
|
+
Finally we are ready to create a new event and see what happens. First we create an event with a default level.
|
269
|
+
|
270
|
+
```ruby
|
271
|
+
AetherObservatory::Examples::TalkboxCallQueueEvent.create
|
272
|
+
```
|
273
|
+
|
274
|
+
Running the create with no parameters will have a default level of `info`. You will see the following output.
|
275
|
+
|
276
|
+
```irb
|
277
|
+
irb(main):058:0> AetherObservatory::Examples::TalkboxCallQueueEvent.create
|
278
|
+
************************************
|
279
|
+
Event processed:
|
280
|
+
Name: "talkbox.call_queues.events.all"
|
281
|
+
Level: info
|
282
|
+
Event Payload: #<AetherObservatory::Examples::TalkboxCallQueueEvent:0x0000aaab112f75d0 @attributes=#<ActiveModel::AttributeSet:0x0000aaab112f5e88 @attributes={"level"=>#<ActiveModel::Attribute::UserProvidedDefault:0x0000aaab112f73a0 @user_provided_value="info", @name="level", @value_before_type_cast="info", @type=#<ActiveModel::Type::Value:0x0000aaab13a76e08 @precision=nil, @scale=nil, @limit=nil>, @original_attribute=nil, @value="info">}>>
|
283
|
+
************************************
|
284
|
+
[AetherObservatory::Examples::TalkboxCallQueueEvent] Create event for topic: [talkbox.call_queues.events.all]
|
285
|
+
[AetherObservatory::Examples::TalkboxCallQueueEvent] Create event for topic: [talkbox.call_queues.events.info]
|
286
|
+
=> nil
|
287
|
+
```
|
288
|
+
|
289
|
+
Next we will try creating a new event but this time we set the `level` to `error`.
|
290
|
+
|
291
|
+
```ruby
|
292
|
+
AetherObservatory::Examples::TalkboxCallQueueEvent.create(level: 'error')
|
293
|
+
```
|
294
|
+
|
295
|
+
As you can see from the output, setting the `level` to `error` will send an event to both classes.
|
296
|
+
|
297
|
+
```irb
|
298
|
+
irb(main):059:0> AetherObservatory::Examples::TalkboxCallQueueEvent.create(level: 'error')
|
299
|
+
************************************
|
300
|
+
Event processed:
|
301
|
+
Name: "talkbox.call_queues.events.all"
|
302
|
+
Level: error
|
303
|
+
Event Payload: #<AetherObservatory::Examples::TalkboxCallQueueEvent:0x0000aaab135cff30 @attributes=#<ActiveModel::AttributeSet:0x0000aaab135cfe18 @attributes={"level"=>#<ActiveModel::Attribute::FromUser:0x0000aaab135cfe68 @name="level", @value_before_type_cast="error", @type=#<ActiveModel::Type::Value:0x0000aaab13a76e08 @precision=nil, @scale=nil, @limit=nil>, @original_attribute=#<ActiveModel::Attribute::UserProvidedDefault:0x0000aaab135e0bc8 @user_provided_value="info", @name="level", @value_before_type_cast="info", @type=#<ActiveModel::Type::Value:0x0000aaab13a76e08 @precision=nil, @scale=nil, @limit=nil>, @original_attribute=nil>, @value="error">}>>
|
304
|
+
************************************
|
305
|
+
[AetherObservatory::Examples::TalkboxCallQueueEvent] Create event for topic: [talkbox.call_queues.events.all]
|
306
|
+
************************************
|
307
|
+
Error Event processed:
|
308
|
+
Name: "talkbox.call_queues.events.error"
|
309
|
+
Level: error
|
310
|
+
Event Payload: #<AetherObservatory::Examples::TalkboxCallQueueEvent:0x0000aaab135cef90 @attributes=#<ActiveModel::AttributeSet:0x0000aaab135ceea0 @attributes={"level"=>#<ActiveModel::Attribute::FromUser:0x0000aaab135cef40 @name="level", @value_before_type_cast="error", @type=#<ActiveModel::Type::Value:0x0000aaab13a76e08 @precision=nil, @scale=nil, @limit=nil>, @original_attribute=#<ActiveModel::Attribute::UserProvidedDefault:0x0000aaab135e0bc8 @user_provided_value="info", @name="level", @value_before_type_cast="info", @type=#<ActiveModel::Type::Value:0x0000aaab13a76e08 @precision=nil, @scale=nil, @limit=nil>, @original_attribute=nil>, @value="error">}>>
|
311
|
+
************************************
|
312
|
+
[AetherObservatory::Examples::TalkboxCallQueueEvent] Create event for topic: [talkbox.call_queues.events.error]
|
313
|
+
=> nil
|
314
|
+
```
|
315
|
+
|
316
|
+
<div align="right">
|
317
|
+
<a href="#aetherobservatory-guide">Top</a>
|
318
|
+
</div>
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_model"
|
4
|
+
|
5
|
+
module AetherObservatory
|
6
|
+
class EventBase
|
7
|
+
include ActiveModel::AttributeAssignment
|
8
|
+
include ActiveModel::Attributes
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def inherited(subclass)
|
12
|
+
super
|
13
|
+
subclass.event_prefix(&event_prefix)
|
14
|
+
end
|
15
|
+
|
16
|
+
def create(**attributes)
|
17
|
+
event = new(**attributes)
|
18
|
+
event_names_with_prefix.each do |event_name_parts|
|
19
|
+
event_name = event_name_parts.filter_map do |part|
|
20
|
+
event.instance_exec(&part) unless part.nil?
|
21
|
+
end.join(".")
|
22
|
+
logger.debug("[#{name}] Create event for topic: [#{event_name}]")
|
23
|
+
ActiveSupport::Notifications.instrument(event_name, event)
|
24
|
+
end
|
25
|
+
|
26
|
+
nil
|
27
|
+
end
|
28
|
+
|
29
|
+
def event_prefix(value = nil, &block)
|
30
|
+
@event_prefix = -> { value } if value.present?
|
31
|
+
@event_prefix = block if block.present?
|
32
|
+
|
33
|
+
@event_prefix
|
34
|
+
end
|
35
|
+
|
36
|
+
def event_name(value = nil, &block)
|
37
|
+
event_names << -> { value } if value.present?
|
38
|
+
event_names << block if block.present?
|
39
|
+
|
40
|
+
nil
|
41
|
+
end
|
42
|
+
|
43
|
+
def event_names_with_prefix
|
44
|
+
event_names.map { |event_name| [event_prefix, event_name] }
|
45
|
+
end
|
46
|
+
|
47
|
+
def event_names
|
48
|
+
@event_names ||= []
|
49
|
+
end
|
50
|
+
|
51
|
+
def logger(value = nil)
|
52
|
+
@logger = value if value.present?
|
53
|
+
|
54
|
+
@logger || AetherObservatory.config.logger
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
delegate :event_name, to: "self.class"
|
59
|
+
delegate :logger, to: "self.class"
|
60
|
+
|
61
|
+
def initialize(attributes = {})
|
62
|
+
super()
|
63
|
+
assign_attributes(attributes) if attributes
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AetherObservatory
|
4
|
+
class ObserverBase
|
5
|
+
class << self
|
6
|
+
def inherited(subclass)
|
7
|
+
super
|
8
|
+
subclass.instance_variable_set(:@subscribed_topics, Set.new)
|
9
|
+
subclass.instance_variable_set(:@state, :stopped)
|
10
|
+
subclass.instance_variable_set(:@subscriptions, {})
|
11
|
+
end
|
12
|
+
|
13
|
+
def start
|
14
|
+
return if started?
|
15
|
+
|
16
|
+
logger.debug("[#{name}] Starting")
|
17
|
+
|
18
|
+
subscribed_to.each do |topic|
|
19
|
+
next if subscriptions.include?(topic)
|
20
|
+
|
21
|
+
register_subscription_to(topic)
|
22
|
+
end
|
23
|
+
|
24
|
+
self.state = :started
|
25
|
+
end
|
26
|
+
|
27
|
+
def stop
|
28
|
+
return if stopped?
|
29
|
+
|
30
|
+
logger.debug("[#{name}] Stopping")
|
31
|
+
|
32
|
+
subscriptions.each_key do |topic|
|
33
|
+
unregister_subscription_to(topic)
|
34
|
+
end
|
35
|
+
|
36
|
+
self.state = :stopped
|
37
|
+
end
|
38
|
+
|
39
|
+
def subscribe_to(topic)
|
40
|
+
subscribed_topics.add(topic)
|
41
|
+
|
42
|
+
return if stopped?
|
43
|
+
|
44
|
+
register_subscription_to(topic)
|
45
|
+
end
|
46
|
+
|
47
|
+
def unsubscribe_from(topic)
|
48
|
+
subscribed_topics.delete(topic)
|
49
|
+
|
50
|
+
return if stopped?
|
51
|
+
|
52
|
+
unregister_subscription_to(topic)
|
53
|
+
end
|
54
|
+
|
55
|
+
def subscribed_to
|
56
|
+
subscribed_topics.to_a
|
57
|
+
end
|
58
|
+
|
59
|
+
def started?
|
60
|
+
state == :started
|
61
|
+
end
|
62
|
+
|
63
|
+
def stopped?
|
64
|
+
state == :stopped
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
attr_reader :subscribed_topics, :subscriptions
|
70
|
+
attr_accessor :state
|
71
|
+
|
72
|
+
def register_subscription_to(topic)
|
73
|
+
return if subscriptions.include?(topic)
|
74
|
+
|
75
|
+
logger.debug("[#{name}] Registering subscription to topic: #{topic.inspect}")
|
76
|
+
|
77
|
+
subscriptions[topic] = ActiveSupport::Notifications.subscribe(topic) do |*args|
|
78
|
+
name.constantize.new(ActiveSupport::Notifications::Event.new(*args)).process
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def unregister_subscription_to(topic)
|
83
|
+
return if subscriptions.exclude?(topic)
|
84
|
+
|
85
|
+
logger.debug("[#{name}] Unregistering subscription to topic: #{topic.inspect}")
|
86
|
+
|
87
|
+
ActiveSupport::Notifications.unsubscribe(subscriptions.delete(topic))
|
88
|
+
end
|
89
|
+
|
90
|
+
def logger(value = nil)
|
91
|
+
@logger = value if value.present?
|
92
|
+
|
93
|
+
@logger || AetherObservatory.config.logger
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
attr_accessor :event
|
98
|
+
|
99
|
+
def initialize(event)
|
100
|
+
self.event = event
|
101
|
+
end
|
102
|
+
|
103
|
+
delegate :name, to: :event, prefix: true
|
104
|
+
delegate :payload, to: :event, prefix: true
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/all"
|
4
|
+
require "aether_observatory/configuration"
|
5
|
+
|
6
|
+
module AetherObservatory
|
7
|
+
mattr_accessor :configuration, default: Configuration
|
8
|
+
|
9
|
+
class << self
|
10
|
+
delegate :configure, :config, to: :configuration
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
require "aether_observatory/event_base"
|
15
|
+
require "aether_observatory/observer_base"
|