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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2077ef49032cd7e88e66307072188bd14f3f5eb60c3889d3eaa2d8e32d398a91
4
- data.tar.gz: db192f1c6a7d6c7629200fdb71152d325ec05fcd27f1acf17d2f6f7a77088a77
3
+ metadata.gz: 93275cd1c618ed75c10cccc91aa7e5c8a6b0f3cca8afceef0d7d241d4820edef
4
+ data.tar.gz: 833c710b283472d05591f52f1c78abe8e19aca73dd519c141956294d3696757a
5
5
  SHA512:
6
- metadata.gz: e80126fd3557847a29603838d917b11fbdc93b617cca9ac17ea2c68471d6c1cef76c9e15656a306bf4959ff6ea80f9615db120fb8c72d37ca8096b3c2ed5c187
7
- data.tar.gz: 4c64c89911619b136db60fc135619c17573410083ce86cf0fc4438254133b8bd1724f0123536393f58b783830a60c46248ba2cf62f58b96b8d4dd0852d52dcfd
6
+ metadata.gz: 74baf13ab8a47615e7eb4d5de5e5c5064f53ce9b5506b171becbf145cc802b70ce3641e1dab38bbc8d25f5e17ad73271046e14f4f786441206717795900c42b5
7
+ data.tar.gz: 0752efbcb2193628bf5a0456c38ac8d3c4005e7e3fd904b76a147a80051b4f5300eaae27c4380663192334eb0b2854331ee5046754c45785ee3262938618d3e5
@@ -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 :stream_name
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
- dependency :get
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 dispatch(message_data)
51
- logger.trace { "Dispatching message (#{LogText.message_data(message_data)})" }
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
- self.class.handler_registry.each do |handler|
54
- handler.(message_data, session: session)
55
+ if Defaults.startup_info?
56
+ print_info
55
57
  end
56
58
 
57
- update_position(message_data.global_position)
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
- def start(&probe)
67
- logger.info(tag: :*) { "Starting consumer: #{self.class.name} (Stream: #{stream_name}, Identifier: #{identifier || '(none)'}, Position: #{subscription.position})" }
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(tag: :*) { "Started consumer: #{self.class.name} (Stream: #{stream_name}, Identifier: #{identifier || '(none)'}, Position: #{subscription.position})" }
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 (Stream Name: #{stream_name})" }
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 (Stream Name: #{stream_name}, Starting Position: #{starting_position})" }
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(stream_name, position_update_interval: nil, poll_interval_milliseconds: nil, identifier: nil, **arguments)
133
- instance = new(stream_name)
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(stream_name, **arguments, &probe)
150
- instance = build stream_name, **arguments
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(stream_name=nil, identifier: nil, handlers: nil)
5
- stream_name ||= StreamName.example
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(stream_name)
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(stream_name=nil)
6
- stream_name ||= StreamName.example
5
+ def self.example(category=nil)
6
+ category ||= Category.example
7
7
 
8
- Example.new(stream_name)
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, stream_name, sleep_duration)
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
- initializer :stream_name, :frequency_milliseconds
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(stream_name, frequency_milliseconds=nil)
17
- frequency_milliseconds ||= Defaults.frequency_milliseconds
19
+ def self.build(frequency_milliseconds=nil)
20
+ instance = new
21
+ instance.frequency_milliseconds = frequency_milliseconds
22
+ instance
23
+ end
18
24
 
19
- new(stream_name, frequency_milliseconds)
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(stream_name, global_position, position)
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(stream_name: nil, data: nil, position: nil, global_position: nil)
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
- Example.build
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
- class Example
9
- include ::Consumer::PositionStore
14
+ def self.example_class(&block)
15
+ Class.new do
16
+ include ::Consumer::PositionStore
10
17
 
11
- attr_accessor :telemetry_sink
18
+ def self.build
19
+ instance = new
20
+ instance.configure
21
+ instance
22
+ end
12
23
 
13
- def self.build
14
- instance = new
15
- instance.configure
16
- instance
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,3 +1,4 @@
1
+ ## Consider whether this is still needed after category rename
1
2
  module Consumer
2
3
  module Controls
3
4
  StreamName = Messaging::Controls::StreamName
@@ -1,8 +1,8 @@
1
1
  module Consumer
2
2
  module Controls
3
3
  module Subscription
4
- def self.example(stream_name: nil, next_batch: nil, position: nil, batch_size: nil, count: nil)
5
- get = Get.example(stream_name: stream_name, batch_size: batch_size, count: count)
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.info(tags: [:position_store, :get]) { "Get position done (Position: #{position || '(none)'})" }
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 (Stream Name: #{get.stream_name}, Position: #{position})" }
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 Name: #{get.stream_name}, Position: #{position})" }
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 (Stream Name: #{get.stream_name}, Position: #{position}, Batch Size: #{batch.count})" }
62
+ logger.debug { "Resupplied (Category: #{get.category}, Position: #{position}, Batch Size: #{batch.count})" }
63
63
  end
64
64
  end
65
65
 
@@ -2,6 +2,9 @@ module Consumer
2
2
  class Subscription
3
3
  module Defaults
4
4
  def self.poll_interval_milliseconds
5
+ env_interval = ENV['POLL_INTERVAL_MILLISECONDS']
6
+ return env_interval.to_i if !env_interval.nil?
7
+
5
8
  100
6
9
  end
7
10
 
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: 1.1.0.0
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: 2019-10-02 00:00:00.000000000 Z
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.0.1
158
+ rubygems_version: 3.1.2
159
159
  signing_key:
160
160
  specification_version: 4
161
- summary: Continuous subscription to a stream and message dispatching to handlers
161
+ summary: Continuous subscription to a category and message dispatching to handlers
162
162
  test_files: []