evt-consumer 0.0.0.1 → 0.2.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.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
|