active_event 0.5.2 → 0.5.3
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/MIT-LICENSE +19 -19
- data/README.md +9 -9
- data/app/models/active_event/event.rb +15 -15
- data/app/models/active_event/event_repository.rb +11 -11
- data/db/migrate/00_create_domain_events.rb +9 -9
- data/lib/active_event/autoload.rb +11 -9
- data/lib/active_event/command.rb +35 -39
- data/lib/active_event/domain.rb +4 -2
- data/lib/active_event/event_server.rb +72 -76
- data/lib/active_event/event_source_server.rb +149 -127
- data/lib/active_event/event_type.rb +29 -28
- data/lib/active_event/replay_server.rb +94 -98
- data/lib/active_event/sse.rb +26 -26
- data/lib/active_event/support/attr_initializer.rb +76 -74
- data/lib/active_event/support/attr_setter.rb +31 -29
- data/lib/active_event/support/autoload.rb +46 -44
- data/lib/active_event/support/autoloader.rb +41 -38
- data/lib/active_event/support/multi_logger.rb +31 -28
- data/lib/active_event/validations.rb +68 -68
- data/lib/active_event/validations_registry.rb +18 -18
- data/lib/active_event/version.rb +1 -1
- data/spec/factories/event_factory.rb +9 -9
- data/spec/lib/command_spec.rb +14 -14
- data/spec/lib/domain_spec.rb +21 -21
- data/spec/lib/event_server_spec.rb +29 -29
- data/spec/lib/event_type_spec.rb +38 -38
- data/spec/lib/replay_server_spec.rb +71 -68
- data/spec/lib/support/attr_initializer_spec.rb +55 -55
- data/spec/lib/support/attr_setter_spec.rb +61 -61
- data/spec/models/event_spec.rb +20 -20
- data/spec/spec_helper.rb +1 -1
- data/spec/support/active_record.rb +40 -38
- metadata +2 -4
- data/lib/active_event/support/hash_buffer.rb +0 -24
- data/lib/active_event/support/ring_buffer.rb +0 -20
@@ -1,28 +1,29 @@
|
|
1
|
-
module ActiveEvent
|
2
|
-
module EventType
|
3
|
-
extend ActiveSupport::Concern
|
4
|
-
include ActiveEvent::Support::AttrInitializer
|
5
|
-
|
6
|
-
def event_type
|
7
|
-
self.class.name
|
8
|
-
end
|
9
|
-
|
10
|
-
def self.create_instance(type, data)
|
11
|
-
Object.const_get(type).new(data)
|
12
|
-
rescue NameError
|
13
|
-
require 'ostruct'
|
14
|
-
OpenStruct.new(data.merge(event_type: type.to_s)).freeze
|
15
|
-
end
|
16
|
-
|
17
|
-
def add_store_infos(hash)
|
18
|
-
store_infos.merge! hash
|
19
|
-
end
|
20
|
-
|
21
|
-
def store_infos
|
22
|
-
@store_infos ||= {}
|
23
|
-
end
|
24
|
-
|
25
|
-
private
|
26
|
-
|
27
|
-
|
28
|
-
end
|
1
|
+
module ActiveEvent
|
2
|
+
module EventType
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
include ActiveEvent::Support::AttrInitializer
|
5
|
+
|
6
|
+
def event_type
|
7
|
+
self.class.name
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.create_instance(type, data)
|
11
|
+
Object.const_get(type).new(data)
|
12
|
+
rescue NameError
|
13
|
+
require 'ostruct'
|
14
|
+
OpenStruct.new(data.merge(event_type: type.to_s)).freeze
|
15
|
+
end
|
16
|
+
|
17
|
+
def add_store_infos(hash)
|
18
|
+
store_infos.merge! hash
|
19
|
+
end
|
20
|
+
|
21
|
+
def store_infos
|
22
|
+
@store_infos ||= {}
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
attr_writer :store_infos
|
28
|
+
end
|
29
|
+
end
|
@@ -1,98 +1,94 @@
|
|
1
|
-
require 'singleton'
|
2
|
-
require 'bunny'
|
3
|
-
require 'thread'
|
4
|
-
module ActiveEvent
|
5
|
-
class ReplayServer
|
6
|
-
include Singleton
|
7
|
-
|
8
|
-
def self.start(options, id)
|
9
|
-
instance.options = options
|
10
|
-
instance.start id
|
11
|
-
end
|
12
|
-
|
13
|
-
def self.update(id)
|
14
|
-
instance.queue << id
|
15
|
-
end
|
16
|
-
|
17
|
-
def start(id)
|
18
|
-
event_connection.start
|
19
|
-
@last_id = id
|
20
|
-
start_republishing
|
21
|
-
send_done_message
|
22
|
-
rescue
|
23
|
-
LOGGER.error e.message
|
24
|
-
LOGGER.error e.backtrace.join("\n")
|
25
|
-
raise e
|
26
|
-
end
|
27
|
-
|
28
|
-
def queue
|
29
|
-
@queue ||= Queue.new
|
30
|
-
end
|
31
|
-
|
32
|
-
def send_done_message
|
33
|
-
resend_exchange.publish 'replay_done'
|
34
|
-
end
|
35
|
-
|
36
|
-
def start_republishing
|
37
|
-
loop do
|
38
|
-
@events = EventRepository.after_id(@last_id).to_a
|
39
|
-
return if @events.empty?
|
40
|
-
republish_events
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def republish_events
|
45
|
-
while
|
46
|
-
return if new_id?
|
47
|
-
republish next_event
|
48
|
-
Thread.pass
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def new_id?
|
53
|
-
unless queue.empty?
|
54
|
-
new_id = queue.pop
|
55
|
-
if new_id < @last_id
|
56
|
-
@last_id = new_id
|
57
|
-
return true
|
58
|
-
end
|
59
|
-
end
|
60
|
-
false
|
61
|
-
end
|
62
|
-
|
63
|
-
def republish(event)
|
64
|
-
type = event.event
|
65
|
-
body = event.data.to_json
|
66
|
-
resend_exchange.publish body,
|
67
|
-
LOGGER.debug "Republished #{type} with #{body}"
|
68
|
-
end
|
69
|
-
|
70
|
-
def next_event
|
71
|
-
e = @events.shift
|
72
|
-
@last_id = e.id
|
73
|
-
e
|
74
|
-
end
|
75
|
-
|
76
|
-
def
|
77
|
-
@events.length > 0
|
78
|
-
end
|
79
|
-
|
80
|
-
def event_connection
|
81
|
-
@event_server ||= Bunny.new URI::Generic.build(options[:event_connection]).to_s
|
82
|
-
end
|
83
|
-
|
84
|
-
def event_channel
|
85
|
-
@event_channel ||= event_connection.create_channel
|
86
|
-
end
|
87
|
-
|
88
|
-
def resend_exchange
|
89
|
-
@resend_exchange ||= event_channel.fanout "resend_#{options[:event_exchange]}"
|
90
|
-
end
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
attr_writer :options
|
97
|
-
end
|
98
|
-
end
|
1
|
+
require 'singleton'
|
2
|
+
require 'bunny'
|
3
|
+
require 'thread'
|
4
|
+
module ActiveEvent
|
5
|
+
class ReplayServer
|
6
|
+
include Singleton
|
7
|
+
|
8
|
+
def self.start(options, id)
|
9
|
+
instance.options = options
|
10
|
+
instance.start id
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.update(id)
|
14
|
+
instance.queue << id
|
15
|
+
end
|
16
|
+
|
17
|
+
def start(id)
|
18
|
+
event_connection.start
|
19
|
+
@last_id = id
|
20
|
+
start_republishing
|
21
|
+
send_done_message
|
22
|
+
rescue => e
|
23
|
+
LOGGER.error e.message
|
24
|
+
LOGGER.error e.backtrace.join("\n")
|
25
|
+
raise e
|
26
|
+
end
|
27
|
+
|
28
|
+
def queue
|
29
|
+
@queue ||= Queue.new
|
30
|
+
end
|
31
|
+
|
32
|
+
def send_done_message
|
33
|
+
resend_exchange.publish 'replay_done'
|
34
|
+
end
|
35
|
+
|
36
|
+
def start_republishing
|
37
|
+
loop do
|
38
|
+
@events = EventRepository.after_id(@last_id).to_a
|
39
|
+
return if @events.empty?
|
40
|
+
republish_events
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def republish_events
|
45
|
+
while next_event?
|
46
|
+
return if new_id?
|
47
|
+
republish next_event
|
48
|
+
Thread.pass
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def new_id?
|
53
|
+
unless queue.empty?
|
54
|
+
new_id = queue.pop
|
55
|
+
if new_id < @last_id
|
56
|
+
@last_id = new_id
|
57
|
+
return true
|
58
|
+
end
|
59
|
+
end
|
60
|
+
false
|
61
|
+
end
|
62
|
+
|
63
|
+
def republish(event)
|
64
|
+
type = event.event
|
65
|
+
body = event.data.to_json
|
66
|
+
resend_exchange.publish body, type: type, headers: {id: event.id, created_at: event.created_at, replayed: true}
|
67
|
+
LOGGER.debug "Republished #{type} with #{body}"
|
68
|
+
end
|
69
|
+
|
70
|
+
def next_event
|
71
|
+
e = @events.shift
|
72
|
+
@last_id = e.id
|
73
|
+
e
|
74
|
+
end
|
75
|
+
|
76
|
+
def next_event?
|
77
|
+
@events.length > 0
|
78
|
+
end
|
79
|
+
|
80
|
+
def event_connection
|
81
|
+
@event_server ||= Bunny.new URI::Generic.build(options[:event_connection]).to_s
|
82
|
+
end
|
83
|
+
|
84
|
+
def event_channel
|
85
|
+
@event_channel ||= event_connection.create_channel
|
86
|
+
end
|
87
|
+
|
88
|
+
def resend_exchange
|
89
|
+
@resend_exchange ||= event_channel.fanout "resend_#{options[:event_exchange]}"
|
90
|
+
end
|
91
|
+
|
92
|
+
attr_accessor :options
|
93
|
+
end
|
94
|
+
end
|
data/lib/active_event/sse.rb
CHANGED
@@ -1,26 +1,26 @@
|
|
1
|
-
require 'json'
|
2
|
-
|
3
|
-
module ActiveEvent
|
4
|
-
class SSE
|
5
|
-
def initialize(io)
|
6
|
-
@io = io
|
7
|
-
end
|
8
|
-
|
9
|
-
def event(event, data = nil, options = {})
|
10
|
-
self.data options.merge(event: event, data: JSON.dump(data))
|
11
|
-
end
|
12
|
-
|
13
|
-
def data(data)
|
14
|
-
data.each_pair do |key, value|
|
15
|
-
(value+"\n").split("\n", -1)[0..-2].each do |v|
|
16
|
-
@io.write "#{key}: #{v}\n"
|
17
|
-
end
|
18
|
-
end
|
19
|
-
@io.write "\n"
|
20
|
-
end
|
21
|
-
|
22
|
-
def close
|
23
|
-
@io.close
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module ActiveEvent
|
4
|
+
class SSE
|
5
|
+
def initialize(io)
|
6
|
+
@io = io
|
7
|
+
end
|
8
|
+
|
9
|
+
def event(event, data = nil, options = {})
|
10
|
+
self.data options.merge(event: event, data: JSON.dump(data))
|
11
|
+
end
|
12
|
+
|
13
|
+
def data(data)
|
14
|
+
data.each_pair do |key, value|
|
15
|
+
(value + "\n").split("\n", -1)[0..-2].each do |v|
|
16
|
+
@io.write "#{key}: #{v}\n"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
@io.write "\n"
|
20
|
+
end
|
21
|
+
|
22
|
+
def close
|
23
|
+
@io.close
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -1,74 +1,76 @@
|
|
1
|
-
module ActiveEvent
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
base
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
end
|
1
|
+
module ActiveEvent
|
2
|
+
module Support
|
3
|
+
class ForbiddenAttributesError < StandardError
|
4
|
+
end
|
5
|
+
|
6
|
+
class UnknownAttributeError < StandardError
|
7
|
+
end
|
8
|
+
|
9
|
+
# Allows to initialize attributes with a hash
|
10
|
+
#
|
11
|
+
# example:
|
12
|
+
# class RgbColor
|
13
|
+
# include ActiveEvent::AttrInitializer
|
14
|
+
# attributes :r, :g, :b
|
15
|
+
# end
|
16
|
+
# green = RgbColor.new r: 250, g: 20, b: 20
|
17
|
+
module AttrInitializer
|
18
|
+
extend ActiveSupport::Concern
|
19
|
+
|
20
|
+
def initialize(*args)
|
21
|
+
hash = (args.last.is_a?(Hash) ? args.pop : {})
|
22
|
+
super
|
23
|
+
check_attributes hash
|
24
|
+
init_attributes hash
|
25
|
+
end
|
26
|
+
|
27
|
+
def freeze
|
28
|
+
attributes.freeze
|
29
|
+
end
|
30
|
+
|
31
|
+
def attributes_except(*args)
|
32
|
+
attributes.reject { |k, _| args.include? k }
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_hash
|
36
|
+
attributes.dup
|
37
|
+
end
|
38
|
+
|
39
|
+
module ClassMethods
|
40
|
+
def self.extended(base)
|
41
|
+
base.attribute_keys = []
|
42
|
+
end
|
43
|
+
|
44
|
+
attr_accessor :attribute_keys
|
45
|
+
|
46
|
+
def attributes(*args)
|
47
|
+
self.attribute_keys += args
|
48
|
+
args.each do |attr|
|
49
|
+
define_method attr, -> { attributes[attr] }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
protected
|
55
|
+
|
56
|
+
attr_accessor :attributes
|
57
|
+
|
58
|
+
def init_attributes(attributes)
|
59
|
+
self.attributes = attributes.symbolize_keys
|
60
|
+
freeze
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def check_attributes(attributes)
|
66
|
+
return if attributes.blank?
|
67
|
+
if attributes.respond_to?(:permitted?) && !attributes.permitted?
|
68
|
+
fail ActiveEvent::Support::ForbiddenAttributesError
|
69
|
+
end
|
70
|
+
(attributes.keys.map(&:to_sym) - self.class.attribute_keys).each do |k|
|
71
|
+
fail ActiveEvent::Support::UnknownAttributeError, "unknown attribute: #{k}"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|