evt-consumer 0.0.0.1 → 0.2.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.rb +18 -1
- data/lib/consumer/actor.rb +45 -0
- data/lib/consumer/consumer.rb +141 -7
- data/lib/consumer/controls.rb +9 -0
- data/lib/consumer/controls/consumer.rb +7 -2
- data/lib/consumer/controls/consumer/incrementing.rb +30 -0
- data/lib/consumer/controls/cycle.rb +20 -0
- data/lib/consumer/controls/error.rb +11 -0
- data/lib/consumer/controls/event_data.rb +5 -3
- data/lib/consumer/controls/event_data/batch.rb +22 -0
- data/lib/consumer/controls/get.rb +41 -0
- data/lib/consumer/controls/get/incrementing.rb +42 -0
- data/lib/consumer/controls/handle.rb +17 -0
- data/lib/consumer/controls/position.rb +6 -2
- data/lib/consumer/controls/position_store/local_file.rb +23 -0
- data/lib/consumer/controls/subscription.rb +25 -0
- data/lib/consumer/defaults.rb +7 -0
- data/lib/consumer/dispatch.rb +43 -0
- data/lib/consumer/dispatch/substitute.rb +29 -0
- data/lib/consumer/handler_registry.rb +63 -0
- data/lib/consumer/log_text.rb +7 -0
- data/lib/consumer/position_store/substitute.rb +30 -0
- data/lib/consumer/subscription.rb +89 -0
- data/lib/consumer/subscription/defaults.rb +13 -0
- data/lib/consumer/subscription/get_batch.rb +17 -0
- data/lib/consumer/substitute.rb +27 -0
- metadata +22 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 00b0c73220714ee6fcf3f270b6ad3060fb31b589
|
4
|
+
data.tar.gz: ea9bda155670320c05c33e501904bca847d7ebee
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8915dd125283bc4a281845ef72557f110ec4c63bac950333c516f4c5c77bfee65878de6207928843b14b99f6692cc6b66b98312f252d5c550a2fad4b1a0450ab
|
7
|
+
data.tar.gz: 18453c9ca467afbfdd96160cf2f8685e7cc51bc37a4e48c1672b63cda5cc64d0cae9ecb441fe3f28079bcd0247aea6e3ca94029ff619f53fd4f180a78a434433
|
data/lib/consumer.rb
CHANGED
@@ -5,7 +5,24 @@ require 'messaging'
|
|
5
5
|
require 'log'
|
6
6
|
|
7
7
|
require 'consumer/log'
|
8
|
+
require 'consumer/log_text'
|
9
|
+
|
10
|
+
require 'consumer/defaults'
|
11
|
+
|
12
|
+
require 'consumer/handler_registry'
|
8
13
|
|
9
|
-
require 'consumer/consumer'
|
10
14
|
require 'consumer/position_store'
|
15
|
+
require 'consumer/position_store/substitute'
|
11
16
|
require 'consumer/position_store/telemetry'
|
17
|
+
|
18
|
+
require 'consumer/dispatch'
|
19
|
+
require 'consumer/dispatch/substitute'
|
20
|
+
|
21
|
+
require 'consumer/subscription'
|
22
|
+
require 'consumer/subscription/defaults'
|
23
|
+
require 'consumer/subscription/get_batch'
|
24
|
+
|
25
|
+
require 'consumer/consumer'
|
26
|
+
require 'consumer/substitute'
|
27
|
+
|
28
|
+
require 'consumer/actor'
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Consumer
|
2
|
+
class Actor
|
3
|
+
include ::Actor
|
4
|
+
include Log::Dependency
|
5
|
+
|
6
|
+
initializer :subscription_address
|
7
|
+
|
8
|
+
dependency :consumer, Consumer
|
9
|
+
|
10
|
+
def self.build(consumer, subscription)
|
11
|
+
instance = new subscription.address
|
12
|
+
instance.consumer = consumer
|
13
|
+
instance.configure
|
14
|
+
instance
|
15
|
+
end
|
16
|
+
|
17
|
+
handle :start do
|
18
|
+
request_batch
|
19
|
+
end
|
20
|
+
|
21
|
+
handle Subscription::GetBatch::Reply do |get_batch_reply|
|
22
|
+
events = get_batch_reply.batch
|
23
|
+
|
24
|
+
logger.trace { "Received batch (Events: #{events.count})" }
|
25
|
+
|
26
|
+
request_batch
|
27
|
+
|
28
|
+
events.each do |event_data|
|
29
|
+
consumer.(event_data)
|
30
|
+
end
|
31
|
+
|
32
|
+
logger.debug { "Batch received (Events: #{events.count})" }
|
33
|
+
end
|
34
|
+
|
35
|
+
def request_batch
|
36
|
+
logger.trace { "Requesting batch" }
|
37
|
+
|
38
|
+
get_batch = Subscription::GetBatch.new address
|
39
|
+
|
40
|
+
send.(get_batch, subscription_address)
|
41
|
+
|
42
|
+
logger.debug { "Send batch request" }
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/lib/consumer/consumer.rb
CHANGED
@@ -1,18 +1,152 @@
|
|
1
1
|
module Consumer
|
2
2
|
def self.included(cls)
|
3
3
|
cls.class_exec do
|
4
|
-
|
4
|
+
include Log::Dependency
|
5
|
+
|
6
|
+
extend Build
|
7
|
+
extend Start
|
8
|
+
|
9
|
+
extend HandleMacro
|
10
|
+
extend PositionStoreMacro
|
11
|
+
|
12
|
+
prepend Configure
|
13
|
+
|
14
|
+
initializer :stream
|
15
|
+
|
16
|
+
attr_writer :position_update_interval
|
17
|
+
|
18
|
+
attr_accessor :cycle_maximum_milliseconds
|
19
|
+
attr_accessor :cycle_timeout_milliseconds
|
20
|
+
|
21
|
+
dependency :dispatch, Dispatch
|
22
|
+
dependency :get
|
23
|
+
dependency :position_store, PositionStore
|
24
|
+
dependency :subscription, Subscription
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def call(event_data)
|
29
|
+
logger.trace { "Dispatching event (#{LogText.event_data event_data})" }
|
30
|
+
|
31
|
+
dispatch.(event_data)
|
32
|
+
|
33
|
+
update_position event_data.global_position
|
34
|
+
|
35
|
+
logger.info { "Event dispatched (#{LogText.event_data event_data})" }
|
36
|
+
|
37
|
+
rescue => error
|
38
|
+
logger.error { "Error raised (Error Class: #{error.class}, Error Message: #{error.message}, #{LogText.event_data event_data})" }
|
39
|
+
error_raised error, event_data
|
40
|
+
end
|
41
|
+
|
42
|
+
Virtual::Method.define self, :configure
|
43
|
+
|
44
|
+
def error_raised(error, _)
|
45
|
+
raise error
|
46
|
+
end
|
47
|
+
|
48
|
+
def update_position(position)
|
49
|
+
logger.trace { "Updating position (Position: #{position}, Interval: #{position_update_interval})" }
|
50
|
+
|
51
|
+
if position % position_update_interval == 0
|
52
|
+
position_store.put position
|
53
|
+
|
54
|
+
logger.debug { "Updated position (Position: #{position}, Interval: #{position_update_interval})" }
|
55
|
+
else
|
56
|
+
logger.debug { "Interval not reached; position not updated (Position: #{position}, Interval: #{position_update_interval})" }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
module LogText
|
61
|
+
def self.event_data(event_data)
|
62
|
+
"Stream: #{event_data.stream_name}, Position: #{event_data.position}, GlobalPosition: #{event_data.global_position}, Type: #{event_data.type}"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
module Configure
|
67
|
+
def configure(batch_size: nil, session: nil)
|
68
|
+
logger.trace { "Configuring (Batch Size: #{batch_size}, Session: #{session.inspect})" }
|
69
|
+
|
70
|
+
super
|
71
|
+
|
72
|
+
position_store_class = self.class.position_store_class
|
73
|
+
|
74
|
+
unless position_store_class.nil?
|
75
|
+
position_store = position_store_class.configure self, stream
|
76
|
+
|
77
|
+
starting_position = position_store.get
|
78
|
+
end
|
79
|
+
|
80
|
+
subscription = Subscription.configure(
|
81
|
+
self,
|
82
|
+
stream,
|
83
|
+
get,
|
84
|
+
position: starting_position,
|
85
|
+
cycle_maximum_milliseconds: cycle_maximum_milliseconds,
|
86
|
+
cycle_timeout_milliseconds: cycle_timeout_milliseconds
|
87
|
+
)
|
88
|
+
|
89
|
+
Dispatch.configure self, handler_registry: self.class.handler_registry
|
90
|
+
|
91
|
+
logger.debug { "Configuring (Batch Size: #{batch_size}, Session: #{session.inspect})" }
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
module Build
|
96
|
+
def build(stream_name, batch_size: nil, session: nil, cycle_timeout_milliseconds: nil, cycle_maximum_milliseconds: nil)
|
97
|
+
stream = EventSource::Stream.canonize stream_name
|
98
|
+
|
99
|
+
instance = new stream
|
100
|
+
instance.cycle_maximum_milliseconds = cycle_maximum_milliseconds
|
101
|
+
instance.cycle_timeout_milliseconds = cycle_timeout_milliseconds
|
102
|
+
instance.configure batch_size: batch_size, session: session
|
103
|
+
instance
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
module Start
|
108
|
+
def start(stream_name, **arguments, &probe)
|
109
|
+
instance = build stream_name, **arguments
|
110
|
+
|
111
|
+
_, subscription_thread = ::Actor::Start.(instance.subscription)
|
112
|
+
|
113
|
+
actor_address = Actor.start instance, instance.subscription
|
114
|
+
|
115
|
+
probe.(instance, actor_address) if probe
|
116
|
+
|
117
|
+
AsyncInvocation::Incorrect
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
module HandleMacro
|
122
|
+
def handle_macro(handler=nil, &block)
|
123
|
+
handler ||= block
|
124
|
+
|
125
|
+
handler_registry.register handler
|
126
|
+
end
|
127
|
+
alias_method :handle, :handle_macro
|
128
|
+
|
129
|
+
def handler_registry
|
130
|
+
@handler_registry ||= HandlerRegistry.new
|
5
131
|
end
|
6
132
|
end
|
7
133
|
|
8
|
-
module
|
9
|
-
def
|
10
|
-
|
134
|
+
module PositionStoreMacro
|
135
|
+
def self.extended(cls)
|
136
|
+
cls.singleton_class.class_exec do
|
137
|
+
attr_accessor :position_store_class
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def position_store_macro(position_store_class, update_interval: nil)
|
142
|
+
update_interval ||= Defaults.position_update_interval
|
143
|
+
|
144
|
+
self.position_store_class = position_store_class
|
11
145
|
|
12
|
-
define_method :
|
13
|
-
|
146
|
+
define_method :position_update_interval do
|
147
|
+
@position_update_interval ||= update_interval
|
14
148
|
end
|
15
149
|
end
|
16
|
-
alias_method :
|
150
|
+
alias_method :position_store, :position_store_macro
|
17
151
|
end
|
18
152
|
end
|
data/lib/consumer/controls.rb
CHANGED
@@ -1,12 +1,21 @@
|
|
1
1
|
require 'messaging/controls'
|
2
2
|
|
3
3
|
require 'consumer/controls/category'
|
4
|
+
require 'consumer/controls/cycle'
|
4
5
|
require 'consumer/controls/event_data'
|
6
|
+
require 'consumer/controls/event_data/batch'
|
7
|
+
require 'consumer/controls/error'
|
8
|
+
require 'consumer/controls/get'
|
9
|
+
require 'consumer/controls/get/incrementing'
|
10
|
+
require 'consumer/controls/handle'
|
5
11
|
require 'consumer/controls/id'
|
6
12
|
require 'consumer/controls/position'
|
7
13
|
require 'consumer/controls/stream'
|
8
14
|
require 'consumer/controls/stream_name'
|
9
15
|
|
10
16
|
require 'consumer/controls/position_store'
|
17
|
+
require 'consumer/controls/position_store/local_file'
|
18
|
+
require 'consumer/controls/subscription'
|
11
19
|
|
12
20
|
require 'consumer/controls/consumer'
|
21
|
+
require 'consumer/controls/consumer/incrementing'
|
@@ -2,13 +2,18 @@ module Consumer
|
|
2
2
|
module Controls
|
3
3
|
module Consumer
|
4
4
|
def self.example
|
5
|
-
Example.new
|
5
|
+
Example.new Stream.example
|
6
6
|
end
|
7
7
|
|
8
8
|
class Example
|
9
9
|
include ::Consumer
|
10
10
|
|
11
|
-
|
11
|
+
handle Handle::Example
|
12
|
+
position_store PositionStore::Example
|
13
|
+
|
14
|
+
def configure(session: nil, batch_size: nil)
|
15
|
+
Get::Example.configure self
|
16
|
+
end
|
12
17
|
end
|
13
18
|
end
|
14
19
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Consumer
|
2
|
+
module Controls
|
3
|
+
module Consumer
|
4
|
+
class Incrementing
|
5
|
+
include ::Consumer
|
6
|
+
|
7
|
+
def self.logger
|
8
|
+
@logger ||= ::Log.get self
|
9
|
+
end
|
10
|
+
|
11
|
+
handle do |event_data|
|
12
|
+
logger.info { "Handled event (StreamName: #{event_data.stream_name}, GlobalPosition: #{event_data.global_position})" }
|
13
|
+
end
|
14
|
+
|
15
|
+
handle do |event_data|
|
16
|
+
logger.debug { event_data.data.pretty_inspect }
|
17
|
+
end
|
18
|
+
|
19
|
+
position_store PositionStore::LocalFile, update_interval: 10
|
20
|
+
|
21
|
+
def configure(session: nil)
|
22
|
+
sleep_duration = ENV['SLEEP_DURATION'] || 100
|
23
|
+
sleep_duration = sleep_duration.to_i
|
24
|
+
|
25
|
+
Get::Incrementing.configure self, sleep_duration
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Consumer
|
2
|
+
module Controls
|
3
|
+
module Cycle
|
4
|
+
def self.example
|
5
|
+
::Cycle.build(
|
6
|
+
maximum_milliseconds: maximum_milliseconds,
|
7
|
+
timeout_milliseconds: timeout_milliseconds
|
8
|
+
)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.maximum_milliseconds
|
12
|
+
1
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.timeout_milliseconds
|
16
|
+
11
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -1,11 +1,13 @@
|
|
1
1
|
module Consumer
|
2
2
|
module Controls
|
3
3
|
module EventData
|
4
|
-
def self.example(stream_name: nil, position: nil, global_position: nil)
|
5
|
-
|
4
|
+
def self.example(stream_name: nil, data: nil, position: nil, global_position: nil)
|
5
|
+
global_position ||= position
|
6
|
+
|
7
|
+
event_data = EventSource::Controls::EventData::Read.example data: data
|
6
8
|
event_data.stream_name = stream_name unless stream_name.nil?
|
7
9
|
event_data.position = position unless position.nil?
|
8
|
-
event_data.global_position unless global_position.nil?
|
10
|
+
event_data.global_position = global_position unless global_position.nil?
|
9
11
|
event_data
|
10
12
|
end
|
11
13
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Consumer
|
2
|
+
module Controls
|
3
|
+
module EventData
|
4
|
+
module Batch
|
5
|
+
def self.example(instances: nil, position: nil)
|
6
|
+
instances ||= size
|
7
|
+
start_position ||= Controls::Position::Global.example
|
8
|
+
|
9
|
+
instances.times.map do |offset|
|
10
|
+
position = start_position + offset
|
11
|
+
|
12
|
+
EventData.example global_position: position
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.size
|
17
|
+
3
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Consumer
|
2
|
+
module Controls
|
3
|
+
module Get
|
4
|
+
def self.example
|
5
|
+
Example.new
|
6
|
+
end
|
7
|
+
|
8
|
+
class Example
|
9
|
+
configure :get
|
10
|
+
|
11
|
+
def self.build
|
12
|
+
new
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(stream_name, position: nil)
|
16
|
+
position ||= 0
|
17
|
+
|
18
|
+
stream = streams.fetch stream_name do
|
19
|
+
return nil
|
20
|
+
end
|
21
|
+
|
22
|
+
stream[position]
|
23
|
+
end
|
24
|
+
|
25
|
+
def set_batch(stream_name, batch, position=nil)
|
26
|
+
position ||= 0
|
27
|
+
|
28
|
+
stream = streams[stream_name]
|
29
|
+
|
30
|
+
stream[position] = batch
|
31
|
+
end
|
32
|
+
|
33
|
+
def streams
|
34
|
+
@streams ||= Hash.new do |hash, key|
|
35
|
+
hash[key] = {}
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Consumer
|
2
|
+
module Controls
|
3
|
+
module Get
|
4
|
+
class Incrementing
|
5
|
+
configure :get
|
6
|
+
|
7
|
+
initializer :sleep_duration
|
8
|
+
|
9
|
+
def self.build(sleep_duration)
|
10
|
+
new sleep_duration
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(stream_name, position: nil)
|
14
|
+
position ||= 0
|
15
|
+
|
16
|
+
sleep Rational(sleep_duration, 1000)
|
17
|
+
|
18
|
+
3.times.map do |offset|
|
19
|
+
EventData.get(
|
20
|
+
stream_name,
|
21
|
+
position + offset,
|
22
|
+
offset
|
23
|
+
)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class EventData
|
29
|
+
def self.get(stream_name, global_position, position)
|
30
|
+
data = { :position => position, :global_position => global_position }
|
31
|
+
|
32
|
+
Controls::EventData.example(
|
33
|
+
stream_name: stream_name,
|
34
|
+
data: data,
|
35
|
+
global_position: global_position,
|
36
|
+
position: position
|
37
|
+
)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -8,8 +8,12 @@ module Consumer
|
|
8
8
|
end
|
9
9
|
|
10
10
|
module Global
|
11
|
-
def self.example
|
12
|
-
|
11
|
+
def self.example(offset: nil)
|
12
|
+
offset ||= 0
|
13
|
+
|
14
|
+
position = EventSource::Controls::EventData::Read.global_position
|
15
|
+
|
16
|
+
position + offset
|
13
17
|
end
|
14
18
|
end
|
15
19
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Consumer
|
2
|
+
module Controls
|
3
|
+
module PositionStore
|
4
|
+
class LocalFile
|
5
|
+
include Consumer::PositionStore
|
6
|
+
|
7
|
+
def get
|
8
|
+
return 0 unless File.exist? path
|
9
|
+
text = File.read path
|
10
|
+
text.to_i
|
11
|
+
end
|
12
|
+
|
13
|
+
def put(position)
|
14
|
+
File.write path, position
|
15
|
+
end
|
16
|
+
|
17
|
+
def path
|
18
|
+
'tmp/control_position_store'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Consumer
|
2
|
+
module Controls
|
3
|
+
module Subscription
|
4
|
+
def self.example(next_batch: nil, batch: nil, position: nil)
|
5
|
+
stream = Stream.example
|
6
|
+
|
7
|
+
get = Get.example
|
8
|
+
|
9
|
+
unless batch.nil?
|
10
|
+
get.set_batch stream.name, batch, position
|
11
|
+
end
|
12
|
+
|
13
|
+
subscription = ::Consumer::Subscription.new stream, get
|
14
|
+
|
15
|
+
subscription.position = position if position
|
16
|
+
|
17
|
+
unless next_batch.nil?
|
18
|
+
subscription.next_batch = next_batch
|
19
|
+
end
|
20
|
+
|
21
|
+
subscription
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Consumer
|
2
|
+
class Dispatch
|
3
|
+
include Log::Dependency
|
4
|
+
|
5
|
+
configure :dispatch
|
6
|
+
|
7
|
+
attr_writer :handler_registry
|
8
|
+
|
9
|
+
def handler_registry
|
10
|
+
@handler_registry ||= HandlerRegistry.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.build(handler_registry: nil)
|
14
|
+
instance = new
|
15
|
+
instance.handler_registry = handler_registry unless handler_registry.nil?
|
16
|
+
instance
|
17
|
+
end
|
18
|
+
|
19
|
+
def call(event_data)
|
20
|
+
logger.trace { "Dispatching event (#{LogText.event_data event_data})" }
|
21
|
+
|
22
|
+
handlers = handler_registry.get
|
23
|
+
|
24
|
+
handlers.each do |handle|
|
25
|
+
handle.(event_data)
|
26
|
+
end
|
27
|
+
|
28
|
+
logger.debug { "Event dispatched (#{LogText.event_data event_data}, Handlers Count: #{handlers.count})" }
|
29
|
+
|
30
|
+
nil
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_proc
|
34
|
+
method :call
|
35
|
+
end
|
36
|
+
|
37
|
+
module Assertions
|
38
|
+
def handler?(handle)
|
39
|
+
handler_registry.registered? handle
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Consumer
|
2
|
+
class Dispatch
|
3
|
+
module Substitute
|
4
|
+
def self.build
|
5
|
+
Dispatch.new
|
6
|
+
end
|
7
|
+
|
8
|
+
class Dispatch
|
9
|
+
def call(event_data)
|
10
|
+
dispatched_events << event_data
|
11
|
+
end
|
12
|
+
|
13
|
+
def dispatched_events
|
14
|
+
@dispatched_events ||= []
|
15
|
+
end
|
16
|
+
|
17
|
+
def dispatched?(event_data=nil, &block)
|
18
|
+
if event_data.nil?
|
19
|
+
block ||= proc { true }
|
20
|
+
else
|
21
|
+
block ||= proc { |e| event_data == e }
|
22
|
+
end
|
23
|
+
|
24
|
+
dispatched_events.any? &block
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Consumer
|
2
|
+
class HandlerRegistry
|
3
|
+
include Log::Dependency
|
4
|
+
|
5
|
+
configure :handler_registry
|
6
|
+
|
7
|
+
def register(handler)
|
8
|
+
logger.trace { "Registering handler (Handler: #{LogText.handler handler})" }
|
9
|
+
|
10
|
+
if registered? handler
|
11
|
+
error_message = "Handler is already registered (Handler: #{LogText.handler handler})"
|
12
|
+
logger.error error_message
|
13
|
+
raise Error, error_message
|
14
|
+
end
|
15
|
+
|
16
|
+
if handler.respond_to? :build
|
17
|
+
instance = handler.build
|
18
|
+
else
|
19
|
+
instance = handler
|
20
|
+
end
|
21
|
+
|
22
|
+
entries << instance
|
23
|
+
|
24
|
+
logger.debug { "Handler registered (Handler: #{LogText.handler handler})" }
|
25
|
+
|
26
|
+
instance
|
27
|
+
end
|
28
|
+
|
29
|
+
def get
|
30
|
+
entries.to_a
|
31
|
+
end
|
32
|
+
|
33
|
+
def registered?(handler)
|
34
|
+
entries.any? do |entry|
|
35
|
+
return true if handler == entry
|
36
|
+
|
37
|
+
next if entry.is_a? Proc
|
38
|
+
|
39
|
+
handler === entry
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def entries
|
44
|
+
@entries ||= Set.new
|
45
|
+
end
|
46
|
+
|
47
|
+
def count
|
48
|
+
entries.count
|
49
|
+
end
|
50
|
+
|
51
|
+
module LogText
|
52
|
+
def self.handler(handler)
|
53
|
+
case handler
|
54
|
+
when Module then handler.name
|
55
|
+
when Proc then '(proc)'
|
56
|
+
else handler.inspect
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
Error = Class.new StandardError
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Consumer
|
2
|
+
module PositionStore
|
3
|
+
module Substitute
|
4
|
+
def self.build
|
5
|
+
PositionStore.new
|
6
|
+
end
|
7
|
+
|
8
|
+
class PositionStore
|
9
|
+
attr_accessor :get_position
|
10
|
+
attr_accessor :put_position
|
11
|
+
|
12
|
+
def get
|
13
|
+
get_position
|
14
|
+
end
|
15
|
+
|
16
|
+
def put(position)
|
17
|
+
self.put_position = position
|
18
|
+
end
|
19
|
+
|
20
|
+
def put?(expected_position=nil)
|
21
|
+
if expected_position.nil?
|
22
|
+
put_position ? true : false
|
23
|
+
else
|
24
|
+
put_position == expected_position
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module Consumer
|
2
|
+
class Subscription
|
3
|
+
include ::Actor
|
4
|
+
include Log::Dependency
|
5
|
+
|
6
|
+
configure :subscription
|
7
|
+
|
8
|
+
initializer :stream, :get
|
9
|
+
|
10
|
+
attr_accessor :next_batch
|
11
|
+
|
12
|
+
attr_writer :position
|
13
|
+
def position
|
14
|
+
@position ||= 0
|
15
|
+
end
|
16
|
+
|
17
|
+
dependency :cycle, Cycle
|
18
|
+
|
19
|
+
def self.build(stream, get, position: nil, cycle_maximum_milliseconds: nil, cycle_timeout_milliseconds: nil)
|
20
|
+
cycle_maximum_milliseconds ||= Defaults.cycle_maximum_milliseconds
|
21
|
+
cycle_timeout_milliseconds ||= Defaults.cycle_timeout_milliseconds
|
22
|
+
|
23
|
+
instance = new stream, get
|
24
|
+
|
25
|
+
instance.position = position
|
26
|
+
|
27
|
+
Cycle.configure(
|
28
|
+
instance,
|
29
|
+
maximum_milliseconds: cycle_maximum_milliseconds,
|
30
|
+
timeout_milliseconds: cycle_timeout_milliseconds
|
31
|
+
)
|
32
|
+
|
33
|
+
instance.configure
|
34
|
+
instance
|
35
|
+
end
|
36
|
+
|
37
|
+
handle :start do
|
38
|
+
:resupply
|
39
|
+
end
|
40
|
+
|
41
|
+
handle :resupply do
|
42
|
+
logger.trace { "Resupplying (StreamName: #{stream.name}, Position: #{position})" }
|
43
|
+
|
44
|
+
batch = cycle.() do
|
45
|
+
get.(stream.name, position: position)
|
46
|
+
end
|
47
|
+
|
48
|
+
if batch.nil? || batch.empty?
|
49
|
+
logger.debug { "Did not resupply; no events available (StreamName: #{stream.name}, Position: #{position})" }
|
50
|
+
|
51
|
+
:resupply
|
52
|
+
else
|
53
|
+
self.next_batch = batch
|
54
|
+
|
55
|
+
logger.debug { "Resupplied (StreamName: #{stream.name}, Position: #{position}, Batch Size: #{batch.count})" }
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
handle :get_batch do |get_batch|
|
60
|
+
logger.trace { "Batch request received" }
|
61
|
+
|
62
|
+
if next_batch.nil?
|
63
|
+
logger.debug { "Could not fulfill batch request; deferring" }
|
64
|
+
|
65
|
+
return get_batch
|
66
|
+
end
|
67
|
+
|
68
|
+
batch = reset_next_batch
|
69
|
+
|
70
|
+
reply_message = get_batch.reply_message batch
|
71
|
+
|
72
|
+
send.(reply_message, get_batch.reply_address)
|
73
|
+
|
74
|
+
logger.debug { "Batch request fulfilled; resupplying (Batch Size: #{batch.count})" }
|
75
|
+
|
76
|
+
:resupply
|
77
|
+
end
|
78
|
+
|
79
|
+
def reset_next_batch
|
80
|
+
batch = next_batch
|
81
|
+
|
82
|
+
self.next_batch = nil
|
83
|
+
|
84
|
+
self.position = batch.last.global_position + 1
|
85
|
+
|
86
|
+
batch
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Consumer
|
2
|
+
class Subscription
|
3
|
+
GetBatch = Struct.new :reply_address
|
4
|
+
|
5
|
+
class GetBatch
|
6
|
+
include ::Actor::Messaging::Message
|
7
|
+
|
8
|
+
def reply_message(batch)
|
9
|
+
Reply.new batch
|
10
|
+
end
|
11
|
+
|
12
|
+
Reply = Struct.new :batch do
|
13
|
+
include ::Actor::Messaging::Message
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Consumer
|
2
|
+
module Substitute
|
3
|
+
def self.build
|
4
|
+
Consumer.new
|
5
|
+
end
|
6
|
+
|
7
|
+
class Consumer
|
8
|
+
def call(event_data)
|
9
|
+
consumed_events << event_data
|
10
|
+
end
|
11
|
+
|
12
|
+
def consumed_events
|
13
|
+
@consumed_events ||= []
|
14
|
+
end
|
15
|
+
|
16
|
+
def consumed?(event_data=nil, &block)
|
17
|
+
if event_data.nil?
|
18
|
+
block ||= proc { true }
|
19
|
+
else
|
20
|
+
block ||= proc { |e| event_data == e }
|
21
|
+
end
|
22
|
+
|
23
|
+
consumed_events.any? &block
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
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: 0.0.0
|
4
|
+
version: 0.2.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: 2017-01-
|
11
|
+
date: 2017-01-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ntl-actor
|
@@ -73,19 +73,39 @@ extensions: []
|
|
73
73
|
extra_rdoc_files: []
|
74
74
|
files:
|
75
75
|
- lib/consumer.rb
|
76
|
+
- lib/consumer/actor.rb
|
76
77
|
- lib/consumer/consumer.rb
|
77
78
|
- lib/consumer/controls.rb
|
78
79
|
- lib/consumer/controls/category.rb
|
79
80
|
- lib/consumer/controls/consumer.rb
|
81
|
+
- lib/consumer/controls/consumer/incrementing.rb
|
82
|
+
- lib/consumer/controls/cycle.rb
|
83
|
+
- lib/consumer/controls/error.rb
|
80
84
|
- lib/consumer/controls/event_data.rb
|
85
|
+
- lib/consumer/controls/event_data/batch.rb
|
86
|
+
- lib/consumer/controls/get.rb
|
87
|
+
- lib/consumer/controls/get/incrementing.rb
|
88
|
+
- lib/consumer/controls/handle.rb
|
81
89
|
- lib/consumer/controls/id.rb
|
82
90
|
- lib/consumer/controls/position.rb
|
83
91
|
- lib/consumer/controls/position_store.rb
|
92
|
+
- lib/consumer/controls/position_store/local_file.rb
|
84
93
|
- lib/consumer/controls/stream.rb
|
85
94
|
- lib/consumer/controls/stream_name.rb
|
95
|
+
- lib/consumer/controls/subscription.rb
|
96
|
+
- lib/consumer/defaults.rb
|
97
|
+
- lib/consumer/dispatch.rb
|
98
|
+
- lib/consumer/dispatch/substitute.rb
|
99
|
+
- lib/consumer/handler_registry.rb
|
86
100
|
- lib/consumer/log.rb
|
101
|
+
- lib/consumer/log_text.rb
|
87
102
|
- lib/consumer/position_store.rb
|
103
|
+
- lib/consumer/position_store/substitute.rb
|
88
104
|
- lib/consumer/position_store/telemetry.rb
|
105
|
+
- lib/consumer/subscription.rb
|
106
|
+
- lib/consumer/subscription/defaults.rb
|
107
|
+
- lib/consumer/subscription/get_batch.rb
|
108
|
+
- lib/consumer/substitute.rb
|
89
109
|
homepage: https://github.com/eventide-project/consumer
|
90
110
|
licenses:
|
91
111
|
- MIT
|