evt-consumer 1.1.0.0 → 2.3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|