evt-consumer 1.1.0.0 → 2.3.0.0
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 +4 -4
- data/lib/consumer/consumer.rb +97 -34
- data/lib/consumer/controls/consumer.rb +3 -3
- data/lib/consumer/controls/consumer/error_handler.rb +4 -4
- data/lib/consumer/controls/consumer/incrementing.rb +1 -1
- data/lib/consumer/controls/get/incrementing.rb +12 -7
- data/lib/consumer/controls/message_data.rb +1 -3
- data/lib/consumer/controls/position_store.rb +30 -9
- data/lib/consumer/controls/stream_name.rb +1 -0
- data/lib/consumer/controls/subscription.rb +2 -2
- data/lib/consumer/position_store.rb +4 -1
- data/lib/consumer/subscription.rb +3 -3
- data/lib/consumer/subscription/defaults.rb +3 -0
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 93275cd1c618ed75c10cccc91aa7e5c8a6b0f3cca8afceef0d7d241d4820edef
|
4
|
+
data.tar.gz: 833c710b283472d05591f52f1c78abe8e19aca73dd519c141956294d3696757a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 74baf13ab8a47615e7eb4d5de5e5c5064f53ce9b5506b171becbf145cc802b70ce3641e1dab38bbc8d25f5e17ad73271046e14f4f786441206717795900c42b5
|
7
|
+
data.tar.gz: 0752efbcb2193628bf5a0456c38ac8d3c4005e7e3fd904b76a147a80051b4f5300eaae27c4380663192334eb0b2854331ee5046754c45785ee3262938618d3e5
|
data/lib/consumer/consumer.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
module Consumer
|
2
|
+
Error = Class.new(RuntimeError)
|
3
|
+
|
2
4
|
def self.included(cls)
|
3
5
|
cls.class_exec do
|
4
6
|
include Dependency
|
@@ -14,7 +16,7 @@ module Consumer
|
|
14
16
|
|
15
17
|
prepend Configure
|
16
18
|
|
17
|
-
initializer :
|
19
|
+
initializer :category
|
18
20
|
|
19
21
|
attr_writer :identifier
|
20
22
|
def identifier
|
@@ -31,11 +33,11 @@ module Consumer
|
|
31
33
|
@position_update_counter ||= 0
|
32
34
|
end
|
33
35
|
|
34
|
-
attr_accessor :session
|
35
|
-
|
36
36
|
attr_accessor :poll_interval_milliseconds
|
37
37
|
|
38
|
-
|
38
|
+
attr_accessor :session
|
39
|
+
|
40
|
+
dependency :get, MessageStore::Get
|
39
41
|
dependency :position_store, PositionStore
|
40
42
|
dependency :subscription, Subscription
|
41
43
|
|
@@ -47,29 +49,18 @@ module Consumer
|
|
47
49
|
end
|
48
50
|
end
|
49
51
|
|
50
|
-
def
|
51
|
-
logger.
|
52
|
+
def start(&probe)
|
53
|
+
logger.info(tags: [:consumer, :start]) { "Starting consumer: #{self.class.name} (Category: #{category}, Identifier: #{identifier || '(none)'}, Position: #{subscription.position})" }
|
52
54
|
|
53
|
-
|
54
|
-
|
55
|
+
if Defaults.startup_info?
|
56
|
+
print_info
|
55
57
|
end
|
56
58
|
|
57
|
-
|
58
|
-
|
59
|
-
logger.info { "Message dispatched (#{LogText.message_data(message_data)})" }
|
60
|
-
|
61
|
-
rescue => error
|
62
|
-
logger.error { "Error raised (Error Class: #{error.class}, Error Message: #{error.message}, #{LogText.message_data(message_data)})" }
|
63
|
-
error_raised(error, message_data)
|
64
|
-
end
|
59
|
+
log_info
|
60
|
+
starting if respond_to?(:starting)
|
65
61
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
starting() if respond_to?(:starting)
|
70
|
-
|
71
|
-
self.class.handler_registry.each do |handler|
|
72
|
-
logger.info(tag: :*) { "Handler: #{handler.name} (Stream Name: #{stream_name}, Consumer: #{self.class.name})" }
|
62
|
+
if not MessageStore::StreamName.category?(category)
|
63
|
+
raise Error, "Consumer's stream name must be a category (Stream Name: #{category})"
|
73
64
|
end
|
74
65
|
|
75
66
|
_, subscription_thread = ::Actor::Start.(subscription)
|
@@ -82,36 +73,88 @@ module Consumer
|
|
82
73
|
probe.(self, [actor_thread, subscription_thread], [actor_address, subscription_address])
|
83
74
|
end
|
84
75
|
|
85
|
-
logger.info(
|
76
|
+
logger.info(tags: [:consumer, :start]) { "Started consumer: #{self.class.name} (Category: #{category}, Identifier: #{identifier || '(none)'}, Position: #{subscription.position})" }
|
86
77
|
|
87
78
|
AsyncInvocation::Incorrect
|
88
79
|
end
|
89
80
|
|
81
|
+
def print_info
|
82
|
+
STDOUT.puts
|
83
|
+
STDOUT.puts " Consumer: #{self.class.name}"
|
84
|
+
STDOUT.puts " Category: #{category}"
|
85
|
+
STDOUT.puts " Position: #{subscription.position}"
|
86
|
+
STDOUT.puts " Identifier: #{identifier || '(none)'}"
|
87
|
+
|
88
|
+
print_startup_info if respond_to?(:print_startup_info)
|
89
|
+
|
90
|
+
STDOUT.puts " Position Location: #{position_store.location || '(none)'}"
|
91
|
+
|
92
|
+
STDOUT.puts
|
93
|
+
|
94
|
+
STDOUT.puts " Handlers:"
|
95
|
+
self.class.handler_registry.each do |handler|
|
96
|
+
STDOUT.puts " Handler: #{handler.name}"
|
97
|
+
STDOUT.puts " Messages: #{handler.message_registry.message_types.join(', ')}"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def log_info
|
102
|
+
logger.info(tags: [:consumer, :start]) { "Category: #{category} (Consumer: #{self.class.name})" }
|
103
|
+
logger.info(tags: [:consumer, :start]) { "Position: #{subscription.position} (Consumer: #{self.class.name})" }
|
104
|
+
logger.info(tags: [:consumer, :start]) { "Identifier: #{identifier || 'nil'} (Consumer: #{self.class.name})" }
|
105
|
+
|
106
|
+
log_startup_info if respond_to?(:log_startup_info)
|
107
|
+
|
108
|
+
logger.info(tags: [:consumer, :start]) { "Position Update Interval: #{position_update_interval.inspect} (Consumer: #{self.class.name})" }
|
109
|
+
|
110
|
+
logger.info(tags: [:consumer, :start]) { "Poll Interval Milliseconds: #{poll_interval_milliseconds.inspect} (Consumer: #{self.class.name})" }
|
111
|
+
|
112
|
+
self.class.handler_registry.each do |handler|
|
113
|
+
logger.info(tags: [:consumer, :start]) { "Handler: #{handler.name} (Consumer: #{self.class.name})" }
|
114
|
+
logger.info(tags: [:consumer, :start]) { "Messages: #{handler.message_registry.message_types.join(', ')} (Handler: #{handler.name}, Consumer: #{self.class.name})" }
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def dispatch(message_data)
|
119
|
+
logger.trace(tags: [:consumer, :dispatch, :message]) { "Dispatching message (#{LogText.message_data(message_data)})" }
|
120
|
+
|
121
|
+
self.class.handler_registry.each do |handler|
|
122
|
+
handler.(message_data, session: session)
|
123
|
+
end
|
124
|
+
|
125
|
+
update_position(message_data.global_position)
|
126
|
+
|
127
|
+
logger.debug(tags: [:consumer, :dispatch, :message]) { "Message dispatched (#{LogText.message_data(message_data)})" }
|
128
|
+
rescue => error
|
129
|
+
logger.error(tag: :*) { "Error raised (Error Class: #{error.class}, Error Message: #{error.message}, #{LogText.message_data(message_data)})" }
|
130
|
+
error_raised(error, message_data)
|
131
|
+
end
|
132
|
+
|
90
133
|
def update_position(position)
|
91
|
-
logger.trace { "Updating position (Global Position: #{position}, Counter: #{position_update_counter}/#{position_update_interval})" }
|
134
|
+
logger.trace(tags: [:consumer, :position]) { "Updating position (Global Position: #{position}, Counter: #{position_update_counter}/#{position_update_interval})" }
|
92
135
|
|
93
136
|
self.position_update_counter += 1
|
94
137
|
|
95
138
|
if position_update_counter >= position_update_interval
|
96
139
|
position_store.put(position)
|
97
140
|
|
98
|
-
logger.debug { "Updated position (Global Position: #{position}, Counter: #{position_update_counter}/#{position_update_interval})" }
|
141
|
+
logger.debug(tags: [:consumer, :position]) { "Updated position (Global Position: #{position}, Counter: #{position_update_counter}/#{position_update_interval})" }
|
99
142
|
|
100
143
|
self.position_update_counter = 0
|
101
144
|
else
|
102
|
-
logger.debug { "Interval not reached; position not updated (Global Position: #{position}, Counter: #{position_update_counter}/#{position_update_interval})" }
|
145
|
+
logger.debug(tags: [:consumer, :position]) { "Interval not reached; position not updated (Global Position: #{position}, Counter: #{position_update_counter}/#{position_update_interval})" }
|
103
146
|
end
|
104
147
|
end
|
105
148
|
|
106
149
|
module LogText
|
107
150
|
def self.message_data(message_data)
|
108
|
-
"Type: #{message_data.type}, Stream: #{message_data.stream_name}, Position: #{message_data.position}, GlobalPosition: #{message_data.global_position}"
|
151
|
+
"Type: #{message_data.type}, Stream Name: #{message_data.stream_name}, Position: #{message_data.position}, GlobalPosition: #{message_data.global_position}"
|
109
152
|
end
|
110
153
|
end
|
111
154
|
|
112
155
|
module Configure
|
113
156
|
def configure(**kwargs)
|
114
|
-
logger.trace { "Configuring (
|
157
|
+
logger.trace(tag: :consumer) { "Configuring (Category: #{category})" }
|
115
158
|
|
116
159
|
super(**kwargs)
|
117
160
|
|
@@ -124,13 +167,13 @@ module Consumer
|
|
124
167
|
poll_interval_milliseconds: poll_interval_milliseconds
|
125
168
|
)
|
126
169
|
|
127
|
-
logger.debug { "Done configuring (
|
170
|
+
logger.debug(tag: :consumer) { "Done configuring (Category: #{category}, Starting Position: #{starting_position})" }
|
128
171
|
end
|
129
172
|
end
|
130
173
|
|
131
174
|
module Build
|
132
|
-
def build(
|
133
|
-
instance = new(
|
175
|
+
def build(category, position_update_interval: nil, poll_interval_milliseconds: nil, identifier: nil, **arguments)
|
176
|
+
instance = new(category)
|
134
177
|
|
135
178
|
unless identifier.nil?
|
136
179
|
instance.identifier = identifier
|
@@ -146,8 +189,8 @@ module Consumer
|
|
146
189
|
end
|
147
190
|
|
148
191
|
module Start
|
149
|
-
def start(
|
150
|
-
instance = build
|
192
|
+
def start(category, **arguments, &probe)
|
193
|
+
instance = build category, **arguments
|
151
194
|
instance.start(&probe)
|
152
195
|
end
|
153
196
|
end
|
@@ -180,4 +223,24 @@ module Consumer
|
|
180
223
|
end
|
181
224
|
end
|
182
225
|
end
|
226
|
+
|
227
|
+
module Defaults
|
228
|
+
def self.startup_info?
|
229
|
+
StartupInfo.get == 'on'
|
230
|
+
end
|
231
|
+
|
232
|
+
module StartupInfo
|
233
|
+
def self.get
|
234
|
+
ENV.fetch(env_var, default)
|
235
|
+
end
|
236
|
+
|
237
|
+
def self.env_var
|
238
|
+
'STARTUP_INFO'
|
239
|
+
end
|
240
|
+
|
241
|
+
def self.default
|
242
|
+
'on'
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
183
246
|
end
|
@@ -1,12 +1,12 @@
|
|
1
1
|
module Consumer
|
2
2
|
module Controls
|
3
3
|
module Consumer
|
4
|
-
def self.example(
|
5
|
-
|
4
|
+
def self.example(category=nil, identifier: nil, handlers: nil)
|
5
|
+
category ||= Category.example
|
6
6
|
|
7
7
|
cls = example_class(identifier: identifier, handlers: handlers)
|
8
8
|
|
9
|
-
cls.new(
|
9
|
+
cls.new(category)
|
10
10
|
end
|
11
11
|
|
12
12
|
def self.example_class(identifier: nil, handlers: nil)
|
@@ -2,10 +2,10 @@ module Consumer
|
|
2
2
|
module Controls
|
3
3
|
module Consumer
|
4
4
|
module ErrorHandler
|
5
|
-
def self.example(
|
6
|
-
|
5
|
+
def self.example(category=nil)
|
6
|
+
category ||= Category.example
|
7
7
|
|
8
|
-
Example.new(
|
8
|
+
Example.new(category)
|
9
9
|
end
|
10
10
|
|
11
11
|
class Example
|
@@ -15,7 +15,7 @@ module Consumer
|
|
15
15
|
attr_accessor :failed_message
|
16
16
|
|
17
17
|
handler Handle::Example
|
18
|
-
handler Handle::RaiseError
|
18
|
+
handler Handle::RaiseError::Example
|
19
19
|
|
20
20
|
def error_raised(error, message)
|
21
21
|
self.handled_error = error
|
@@ -32,7 +32,7 @@ module Consumer
|
|
32
32
|
sleep_duration = ENV['SLEEP_DURATION'] || 100
|
33
33
|
sleep_duration = sleep_duration.to_i
|
34
34
|
|
35
|
-
Get::Incrementing.configure(self,
|
35
|
+
Get::Incrementing.configure(self, sleep_duration)
|
36
36
|
|
37
37
|
PositionStore::File.configure(self, identifier: identifier)
|
38
38
|
end
|
@@ -7,16 +7,23 @@ module Consumer
|
|
7
7
|
|
8
8
|
configure :get
|
9
9
|
|
10
|
-
|
10
|
+
def frequency_milliseconds
|
11
|
+
@frequency_milliseconds ||= Defaults.frequency_milliseconds
|
12
|
+
end
|
13
|
+
attr_writer :frequency_milliseconds
|
11
14
|
|
12
15
|
def frequency_seconds
|
13
16
|
frequency_milliseconds.to_f / 1000
|
14
17
|
end
|
15
18
|
|
16
|
-
def self.build(
|
17
|
-
|
19
|
+
def self.build(frequency_milliseconds=nil)
|
20
|
+
instance = new
|
21
|
+
instance.frequency_milliseconds = frequency_milliseconds
|
22
|
+
instance
|
23
|
+
end
|
18
24
|
|
19
|
-
|
25
|
+
def category
|
26
|
+
Category.example
|
20
27
|
end
|
21
28
|
|
22
29
|
def batch_size
|
@@ -30,7 +37,6 @@ module Consumer
|
|
30
37
|
|
31
38
|
batch_size.times.map do |offset|
|
32
39
|
MessageData.example(
|
33
|
-
stream_name,
|
34
40
|
position + offset,
|
35
41
|
offset
|
36
42
|
)
|
@@ -48,14 +54,13 @@ module Consumer
|
|
48
54
|
end
|
49
55
|
|
50
56
|
class MessageData
|
51
|
-
def self.example(
|
57
|
+
def self.example(global_position, position)
|
52
58
|
data = {
|
53
59
|
:position => position,
|
54
60
|
:global_position => global_position
|
55
61
|
}
|
56
62
|
|
57
63
|
Controls::MessageData.example(
|
58
|
-
stream_name: stream_name,
|
59
64
|
data: data,
|
60
65
|
global_position: global_position,
|
61
66
|
position: position
|
@@ -1,13 +1,11 @@
|
|
1
1
|
module Consumer
|
2
2
|
module Controls
|
3
3
|
module MessageData
|
4
|
-
def self.example(
|
4
|
+
def self.example(data: nil, position: nil, global_position: nil)
|
5
5
|
global_position ||= position
|
6
6
|
|
7
7
|
message_data = MessageStore::Controls::MessageData::Read.example(data: data)
|
8
8
|
|
9
|
-
message_data.stream_name = stream_name unless stream_name.nil?
|
10
|
-
|
11
9
|
message_data.position = position unless position.nil?
|
12
10
|
message_data.global_position = global_position unless global_position.nil?
|
13
11
|
|
@@ -1,20 +1,35 @@
|
|
1
1
|
module Consumer
|
2
2
|
module Controls
|
3
3
|
module PositionStore
|
4
|
-
def self.example
|
5
|
-
|
4
|
+
def self.example(&block)
|
5
|
+
if block.nil?
|
6
|
+
cls = Example
|
7
|
+
else
|
8
|
+
cls = example_class(&block)
|
9
|
+
end
|
10
|
+
|
11
|
+
cls.build
|
6
12
|
end
|
7
13
|
|
8
|
-
|
9
|
-
|
14
|
+
def self.example_class(&block)
|
15
|
+
Class.new do
|
16
|
+
include ::Consumer::PositionStore
|
10
17
|
|
11
|
-
|
18
|
+
def self.build
|
19
|
+
instance = new
|
20
|
+
instance.configure
|
21
|
+
instance
|
22
|
+
end
|
12
23
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
24
|
+
def configure
|
25
|
+
end
|
26
|
+
|
27
|
+
class_exec(&block) unless block.nil?
|
17
28
|
end
|
29
|
+
end
|
30
|
+
|
31
|
+
Example = example_class do
|
32
|
+
attr_accessor :telemetry_sink
|
18
33
|
|
19
34
|
def configure
|
20
35
|
self.telemetry_sink = ::Consumer::PositionStore::Telemetry::Sink.new
|
@@ -29,6 +44,12 @@ module Consumer
|
|
29
44
|
def put(_)
|
30
45
|
end
|
31
46
|
end
|
47
|
+
|
48
|
+
module Location
|
49
|
+
def self.example
|
50
|
+
'somePositionStream'
|
51
|
+
end
|
52
|
+
end
|
32
53
|
end
|
33
54
|
end
|
34
55
|
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
module Consumer
|
2
2
|
module Controls
|
3
3
|
module Subscription
|
4
|
-
def self.example(
|
5
|
-
get = Get.example(stream_name:
|
4
|
+
def self.example(category: nil, next_batch: nil, position: nil, batch_size: nil, count: nil)
|
5
|
+
get = Get.example(stream_name: category, batch_size: batch_size, count: count)
|
6
6
|
|
7
7
|
subscription = ::Consumer::Subscription.new(get)
|
8
8
|
|
@@ -3,6 +3,7 @@ module Consumer
|
|
3
3
|
def self.included(cls)
|
4
4
|
cls.class_exec do
|
5
5
|
include Dependency
|
6
|
+
include Virtual
|
6
7
|
include Log::Dependency
|
7
8
|
|
8
9
|
extend Build
|
@@ -13,6 +14,8 @@ module Consumer
|
|
13
14
|
prepend Put
|
14
15
|
|
15
16
|
dependency :telemetry, ::Telemetry
|
17
|
+
|
18
|
+
virtual :location
|
16
19
|
end
|
17
20
|
end
|
18
21
|
|
@@ -60,7 +63,7 @@ module Consumer
|
|
60
63
|
|
61
64
|
position = super
|
62
65
|
|
63
|
-
logger.
|
66
|
+
logger.debug(tags: [:position_store, :get]) { "Get position done (Position: #{position || '(none)'})" }
|
64
67
|
|
65
68
|
telemetry.record(:get, Telemetry::Get.new(position))
|
66
69
|
|
@@ -46,20 +46,20 @@ module Consumer
|
|
46
46
|
end
|
47
47
|
|
48
48
|
handle :resupply do
|
49
|
-
logger.trace { "Resupplying (
|
49
|
+
logger.trace { "Resupplying (Category: #{get.category}, Position: #{position})" }
|
50
50
|
|
51
51
|
batch = poll.() do
|
52
52
|
get.(position)
|
53
53
|
end
|
54
54
|
|
55
55
|
if batch.nil? || batch.empty?
|
56
|
-
logger.debug { "Did not resupply; no events available (Stream
|
56
|
+
logger.debug { "Did not resupply; no events available (Stream: #{get.stream_name}, Position: #{position})" }
|
57
57
|
|
58
58
|
:resupply
|
59
59
|
else
|
60
60
|
self.next_batch = batch
|
61
61
|
|
62
|
-
logger.debug { "Resupplied (
|
62
|
+
logger.debug { "Resupplied (Category: #{get.category}, Position: #{position}, Batch Size: #{batch.count})" }
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: evt-consumer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.3.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- The Eventide Project
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-06-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ntl-actor
|
@@ -155,8 +155,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
155
155
|
- !ruby/object:Gem::Version
|
156
156
|
version: '0'
|
157
157
|
requirements: []
|
158
|
-
rubygems_version: 3.
|
158
|
+
rubygems_version: 3.1.2
|
159
159
|
signing_key:
|
160
160
|
specification_version: 4
|
161
|
-
summary: Continuous subscription to a
|
161
|
+
summary: Continuous subscription to a category and message dispatching to handlers
|
162
162
|
test_files: []
|