aggro 0.0.3 → 0.0.4
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/.travis.yml +1 -5
- data/aggro.gemspec +1 -3
- data/lib/aggro.rb +25 -7
- data/lib/aggro/aggregate.rb +33 -6
- data/lib/aggro/attribute_dsl.rb +8 -0
- data/lib/aggro/client.rb +4 -0
- data/lib/aggro/cluster_config.rb +5 -0
- data/lib/aggro/concurrent_actor.rb +1 -1
- data/lib/aggro/event_bus.rb +5 -2
- data/lib/aggro/event_serializer.rb +2 -2
- data/lib/aggro/file_store.rb +2 -2
- data/lib/aggro/file_store/reader.rb +11 -3
- data/lib/aggro/file_store/writer.rb +2 -2
- data/lib/aggro/handler/query.rb +19 -7
- data/lib/aggro/logging.rb +16 -0
- data/lib/aggro/marshal_stream.rb +123 -0
- data/lib/aggro/message/events.rb +6 -2
- data/lib/aggro/message/server_error.rb +20 -0
- data/lib/aggro/node.rb +3 -1
- data/lib/aggro/projection.rb +1 -0
- data/lib/aggro/server.rb +1 -5
- data/lib/aggro/subscription.rb +16 -2
- data/lib/aggro/transform/boolean.rb +14 -2
- data/lib/aggro/transform/date.rb +22 -0
- data/lib/aggro/transform/string.rb +2 -2
- data/lib/aggro/transform/time.rb +22 -0
- data/lib/aggro/version.rb +1 -1
- data/lib/aggro/zeromq_transport.rb +44 -0
- data/lib/aggro/{nanomsg_transport → zeromq_transport}/client.rb +11 -9
- data/lib/aggro/{nanomsg_transport → zeromq_transport}/publisher.rb +11 -8
- data/lib/aggro/zeromq_transport/server.rb +92 -0
- data/lib/aggro/{nanomsg_transport → zeromq_transport}/subscriber.rb +23 -24
- data/spec/lib/aggro/event_serializer_spec.rb +1 -1
- data/spec/lib/aggro/file_store/reader_spec.rb +2 -1
- data/spec/lib/aggro/file_store/writer_spec.rb +10 -7
- data/spec/lib/aggro/local_node_spec.rb +2 -2
- data/spec/lib/aggro/marshal_stream_spec.rb +17 -0
- data/spec/lib/aggro/message/events_spec.rb +4 -3
- data/spec/lib/aggro/node_spec.rb +3 -3
- data/spec/lib/aggro/subscription_spec.rb +4 -2
- data/spec/lib/aggro/{nanomsg_transport_spec.rb → zeromq_transport_spec.rb} +11 -7
- data/spec/spec_helper.rb +8 -1
- metadata +17 -50
- data/lib/aggro/abstract_store.rb +0 -12
- data/lib/aggro/nanomsg_transport/connection.rb +0 -98
- data/lib/aggro/nanomsg_transport/publish.rb +0 -17
- data/lib/aggro/nanomsg_transport/raw_reply.rb +0 -18
- data/lib/aggro/nanomsg_transport/raw_request.rb +0 -18
- data/lib/aggro/nanomsg_transport/reply.rb +0 -17
- data/lib/aggro/nanomsg_transport/request.rb +0 -17
- data/lib/aggro/nanomsg_transport/server.rb +0 -84
- data/lib/aggro/nanomsg_transport/socket_error.rb +0 -20
- data/lib/aggro/nanomsg_transport/subscribe.rb +0 -27
- data/spec/lib/aggro/abstract_store_spec.rb +0 -15
- data/spec/lib/aggro/nanomsg_transport/socket_error_spec.rb +0 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 87f15442c120f8553416f7cbb2b18e345a1dd0a3
|
4
|
+
data.tar.gz: 7963f8f2fbec1eea359339daa103b52eef7e450d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 00dddfea09997a76c17f5ed118b52be604dd4e9b412f3cfc1cacc58656a3a7b87bb2aad41eeb64ee64a2b2583e307816987a85af2bf7d4a3385f54574fe71999
|
7
|
+
data.tar.gz: c99308f889a0bf8906515dbbbf36025cb322d1cabf27a6b4e58666a780bda2d784055dc57feb48da00da6e06e1136eeef814059b8508005b9999679996e9f378
|
data/.travis.yml
CHANGED
@@ -1,15 +1,11 @@
|
|
1
1
|
language: ruby
|
2
2
|
rvm:
|
3
3
|
- 2.2.0
|
4
|
-
- jruby-19mode
|
5
4
|
- ruby-head
|
6
5
|
- jruby-head
|
7
6
|
matrix:
|
8
7
|
allow_failures:
|
9
|
-
- rvm: jruby-19mode
|
10
8
|
- rvm: jruby-head
|
11
9
|
- rvm: ruby-head
|
12
10
|
script: bundle exec rspec
|
13
|
-
before_install:
|
14
|
-
- git clone git://github.com/nanomsg/nanomsg.git
|
15
|
-
- cd nanomsg && ./autogen.sh && ./configure && sudo make install && sudo ldconfig && cd ${TRAVIS_BUILD_DIR}
|
11
|
+
before_install: sudo apt-get install libzmq3-dev
|
data/aggro.gemspec
CHANGED
@@ -29,7 +29,5 @@ Gem::Specification.new do |spec|
|
|
29
29
|
spec.add_runtime_dependency 'concurrent-ruby'
|
30
30
|
spec.add_runtime_dependency 'consistent-hashing'
|
31
31
|
spec.add_runtime_dependency 'invokr'
|
32
|
-
spec.add_runtime_dependency '
|
33
|
-
spec.add_runtime_dependency 'nn-core'
|
34
|
-
spec.add_runtime_dependency 'object-stream'
|
32
|
+
spec.add_runtime_dependency 'zeromqrb'
|
35
33
|
end
|
data/lib/aggro.rb
CHANGED
@@ -6,9 +6,9 @@ require 'concurrent'
|
|
6
6
|
require 'consistent_hashing'
|
7
7
|
require 'invokr'
|
8
8
|
require 'fileutils'
|
9
|
-
require '
|
10
|
-
require 'object-stream'
|
9
|
+
require 'uri'
|
11
10
|
require 'yaml'
|
11
|
+
require 'zero_mq'
|
12
12
|
|
13
13
|
# Private: Define methods to protect handlers from code reloading.
|
14
14
|
module Aggro
|
@@ -31,9 +31,9 @@ module Aggro
|
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
|
-
require 'aggro/abstract_store'
|
35
34
|
require 'aggro/attribute_dsl'
|
36
35
|
require 'aggro/event_dsl'
|
36
|
+
require 'aggro/logging'
|
37
37
|
|
38
38
|
require 'aggro/message/ask'
|
39
39
|
require 'aggro/message/command'
|
@@ -47,6 +47,7 @@ require 'aggro/message/ok'
|
|
47
47
|
require 'aggro/message/publisher_endpoint_inquiry'
|
48
48
|
require 'aggro/message/query'
|
49
49
|
require 'aggro/message/result'
|
50
|
+
require 'aggro/message/server_error'
|
50
51
|
require 'aggro/message/start_saga'
|
51
52
|
require 'aggro/message/unhandled_operation'
|
52
53
|
require 'aggro/message/unknown_operation'
|
@@ -58,12 +59,14 @@ require 'aggro/handler/query'
|
|
58
59
|
require 'aggro/handler/start_saga'
|
59
60
|
|
60
61
|
require 'aggro/transform/boolean'
|
62
|
+
require 'aggro/transform/date'
|
61
63
|
require 'aggro/transform/email'
|
62
64
|
require 'aggro/transform/id'
|
63
65
|
require 'aggro/transform/integer'
|
64
66
|
require 'aggro/transform/money'
|
65
67
|
require 'aggro/transform/noop'
|
66
68
|
require 'aggro/transform/string'
|
69
|
+
require 'aggro/transform/time'
|
67
70
|
require 'aggro/transform/time_interval'
|
68
71
|
|
69
72
|
require 'aggro/aggregate'
|
@@ -81,9 +84,9 @@ require 'aggro/event_serializer'
|
|
81
84
|
require 'aggro/file_store'
|
82
85
|
require 'aggro/local_node'
|
83
86
|
require 'aggro/locator'
|
87
|
+
require 'aggro/marshal_stream'
|
84
88
|
require 'aggro/message_parser'
|
85
89
|
require 'aggro/message_router'
|
86
|
-
require 'aggro/nanomsg_transport'
|
87
90
|
require 'aggro/node'
|
88
91
|
require 'aggro/node_list'
|
89
92
|
require 'aggro/projection'
|
@@ -94,6 +97,7 @@ require 'aggro/saga_status'
|
|
94
97
|
require 'aggro/server'
|
95
98
|
require 'aggro/subscriber'
|
96
99
|
require 'aggro/subscription'
|
100
|
+
require 'aggro/zeromq_transport'
|
97
101
|
|
98
102
|
# Public: Module for namespacing and configuration methods.
|
99
103
|
module Aggro
|
@@ -112,6 +116,7 @@ module Aggro
|
|
112
116
|
|
113
117
|
class << self
|
114
118
|
attr_writer :data_dir
|
119
|
+
attr_writer :logger
|
115
120
|
attr_writer :port
|
116
121
|
attr_writer :publisher_port
|
117
122
|
attr_writer :transport
|
@@ -159,6 +164,10 @@ module Aggro
|
|
159
164
|
end
|
160
165
|
end
|
161
166
|
|
167
|
+
def logger
|
168
|
+
@logger ||= -> (_level, _progname, _message = nil, &_block) {}
|
169
|
+
end
|
170
|
+
|
162
171
|
def node_list
|
163
172
|
@node_list ||= begin
|
164
173
|
NodeList.new.tap do |node_list|
|
@@ -182,14 +191,23 @@ module Aggro
|
|
182
191
|
@event_bus.shutdown if @event_bus
|
183
192
|
@event_bus = nil
|
184
193
|
@local_node = nil
|
185
|
-
@node_list = nil
|
194
|
+
reset_clients && @node_list = nil
|
186
195
|
@port = nil
|
187
|
-
@publisher = nil
|
188
196
|
@publisher_port = nil
|
197
|
+
@server.stop if @server
|
189
198
|
@server = nil
|
190
199
|
@store = nil
|
191
200
|
end
|
192
201
|
|
202
|
+
def reset_clients
|
203
|
+
return unless @node_list
|
204
|
+
|
205
|
+
@node_list.nodes
|
206
|
+
.select { |node| node.is_a? Node }
|
207
|
+
.map(&:client)
|
208
|
+
.each(&:disconnect!)
|
209
|
+
end
|
210
|
+
|
193
211
|
def server
|
194
212
|
return unless cluster_config.server_node?
|
195
213
|
|
@@ -201,6 +219,6 @@ module Aggro
|
|
201
219
|
end
|
202
220
|
|
203
221
|
def transport
|
204
|
-
@transport ||=
|
222
|
+
@transport ||= ZeroMQTransport
|
205
223
|
end
|
206
224
|
end
|
data/lib/aggro/aggregate.rb
CHANGED
@@ -3,16 +3,15 @@ module Aggro
|
|
3
3
|
module Aggregate
|
4
4
|
extend ActiveSupport::Concern
|
5
5
|
include EventDSL
|
6
|
+
include Logging
|
6
7
|
|
7
8
|
def initialize(id)
|
8
9
|
@id = id
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
h.merge name => klass.new(id)
|
13
|
-
end
|
11
|
+
start_projections
|
12
|
+
restore_from_event_stream
|
14
13
|
|
15
|
-
|
14
|
+
log INFO, 'Restored to memory'
|
16
15
|
end
|
17
16
|
|
18
17
|
private
|
@@ -24,6 +23,10 @@ module Aggro
|
|
24
23
|
|
25
24
|
handler = self.class.handler_for_command(command.class)
|
26
25
|
instance_exec command, &handler
|
26
|
+
rescue => e
|
27
|
+
log ERROR, "Couldn't apply command\n#{e}\n#{e.backtrace.join "\n"}"
|
28
|
+
|
29
|
+
raise e
|
27
30
|
ensure
|
28
31
|
@_context = nil
|
29
32
|
end
|
@@ -34,15 +37,35 @@ module Aggro
|
|
34
37
|
@event_caller ||= EventProxy.new(self, @id)
|
35
38
|
end
|
36
39
|
|
40
|
+
def log(level, message, &block)
|
41
|
+
super level, "#{self.class}/#{@id}", message, &block
|
42
|
+
end
|
43
|
+
|
44
|
+
def restore_from_event_stream
|
45
|
+
Aggro.event_bus.subscribe(@id, self)
|
46
|
+
rescue => e
|
47
|
+
log FATAL, "Couldn't restore from events\n#{e}\n#{e.backtrace.join "\n"}"
|
48
|
+
end
|
49
|
+
|
37
50
|
def run_query(query)
|
38
51
|
return unless self.class.responds_to? query
|
39
52
|
|
40
53
|
handler = self.class.handler_for_query(query.class)
|
41
54
|
instance_exec query, &handler
|
42
|
-
rescue
|
55
|
+
rescue => e
|
56
|
+
log ERROR, "Couldn't complete query\n#{e}\n#{e.backtrace.join "\n"}"
|
43
57
|
QueryError.new(e)
|
44
58
|
end
|
45
59
|
|
60
|
+
def start_projections
|
61
|
+
@projections = self.class.projections.reduce({}) do |h, (name, klass)|
|
62
|
+
class_eval { define_method(name) { @projections[name] } }
|
63
|
+
h.merge name => klass.new(@id)
|
64
|
+
end
|
65
|
+
rescue => e
|
66
|
+
log FATAL, "Couldn't start projections\n#{e}\n#{e.backtrace.join "\n"}"
|
67
|
+
end
|
68
|
+
|
46
69
|
class_methods do
|
47
70
|
def allows(command_class, &block)
|
48
71
|
command_handlers[command_class] = block if block
|
@@ -53,10 +76,14 @@ module Aggro
|
|
53
76
|
end
|
54
77
|
|
55
78
|
def create(id = SecureRandom.uuid)
|
79
|
+
fail ArgumentError unless id && id.length == 36
|
80
|
+
|
56
81
|
find(id).create
|
57
82
|
end
|
58
83
|
|
59
84
|
def find(id)
|
85
|
+
fail ArgumentError unless id && id.length == 36
|
86
|
+
|
60
87
|
AggregateRef.new id, name
|
61
88
|
end
|
62
89
|
|
data/lib/aggro/attribute_dsl.rb
CHANGED
@@ -43,6 +43,10 @@ module Aggro
|
|
43
43
|
create_attrs name, Transform::Boolean
|
44
44
|
end
|
45
45
|
|
46
|
+
def date(name)
|
47
|
+
create_attrs name, Transform::Date
|
48
|
+
end
|
49
|
+
|
46
50
|
def email(name)
|
47
51
|
create_attrs name, Transform::Email
|
48
52
|
end
|
@@ -72,6 +76,10 @@ module Aggro
|
|
72
76
|
create_attrs name, Transform::String
|
73
77
|
end
|
74
78
|
|
79
|
+
def time(name)
|
80
|
+
create_attrs name, Transform::Time
|
81
|
+
end
|
82
|
+
|
75
83
|
def time_interval(name)
|
76
84
|
require 'time-interval'
|
77
85
|
|
data/lib/aggro/client.rb
CHANGED
data/lib/aggro/cluster_config.rb
CHANGED
data/lib/aggro/event_bus.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
module Aggro
|
2
2
|
# Public: Publishes events to any subscribed listeners.
|
3
3
|
class EventBus
|
4
|
+
attr_reader :remote_publishers
|
5
|
+
|
4
6
|
def initialize
|
5
7
|
@remote_publishers = {}
|
6
8
|
end
|
@@ -11,6 +13,7 @@ module Aggro
|
|
11
13
|
return unless subscriptions.key? topic
|
12
14
|
|
13
15
|
subscriptions[topic].each do |subscription|
|
16
|
+
sleep 0.01 until subscription.caught_up
|
14
17
|
subscription.handle_event event
|
15
18
|
end
|
16
19
|
end
|
@@ -39,8 +42,6 @@ module Aggro
|
|
39
42
|
|
40
43
|
private
|
41
44
|
|
42
|
-
attr_reader :remote_publishers
|
43
|
-
|
44
45
|
def catchup_local(topic, subscription)
|
45
46
|
Aggro.store.read([topic]).first.events.each do |event|
|
46
47
|
subscription.handle_event event
|
@@ -66,6 +67,8 @@ module Aggro
|
|
66
67
|
else
|
67
68
|
catchup_remote(topic, subscription, node)
|
68
69
|
end
|
70
|
+
|
71
|
+
subscription.notify_subscription_caught_up
|
69
72
|
end
|
70
73
|
|
71
74
|
def handle_events(topic, events)
|
@@ -4,11 +4,11 @@ module Aggro
|
|
4
4
|
module_function
|
5
5
|
|
6
6
|
def deserialize(serialized)
|
7
|
-
|
7
|
+
Event.new(serialized[0], Time.parse(serialized[1]), serialized[2])
|
8
8
|
end
|
9
9
|
|
10
10
|
def serialize(deserialized)
|
11
|
-
|
11
|
+
[deserialized.name, deserialized.occured_at.iso8601, deserialized.details]
|
12
12
|
end
|
13
13
|
end
|
14
14
|
end
|
data/lib/aggro/file_store.rb
CHANGED
@@ -3,7 +3,7 @@ require 'aggro/file_store/writer'
|
|
3
3
|
|
4
4
|
module Aggro
|
5
5
|
# Public: Stores and retrieves events by serializing them to flat files.
|
6
|
-
class FileStore
|
6
|
+
class FileStore
|
7
7
|
INDEX_DIRECTORY = 'indexes'.freeze
|
8
8
|
EVENT_DIRECTORY = 'events'.freeze
|
9
9
|
REGISTRY_FILE = 'registry'.freeze
|
@@ -84,7 +84,7 @@ module Aggro
|
|
84
84
|
|
85
85
|
def initialize_registry
|
86
86
|
File.open(@registry_file) do |file|
|
87
|
-
|
87
|
+
MarshalStream.new(file).each do |id, type|
|
88
88
|
registry[id] = type
|
89
89
|
end
|
90
90
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module Aggro
|
2
|
-
class FileStore
|
2
|
+
class FileStore
|
3
3
|
# Private: Deserialized events from an IO object.
|
4
4
|
class Reader
|
5
5
|
def initialize(data_io, index_io)
|
@@ -8,13 +8,21 @@ module Aggro
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def read
|
11
|
-
|
11
|
+
Enumerator.new do |yielder|
|
12
|
+
stream.each do |raw_event|
|
13
|
+
yielder << EventSerializer.deserialize(raw_event)
|
14
|
+
end
|
15
|
+
end
|
12
16
|
end
|
13
17
|
|
14
18
|
private
|
15
19
|
|
16
20
|
def index
|
17
|
-
@index ||=
|
21
|
+
@index ||= MarshalStream.new @index_io
|
22
|
+
end
|
23
|
+
|
24
|
+
def stream
|
25
|
+
@stream ||= MarshalStream.new @data_io
|
18
26
|
end
|
19
27
|
end
|
20
28
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module Aggro
|
2
|
-
class FileStore
|
2
|
+
class FileStore
|
3
3
|
# Private: Serializes events to an IO object.
|
4
4
|
class Writer
|
5
5
|
def initialize(data_io, index_io)
|
@@ -9,7 +9,7 @@ module Aggro
|
|
9
9
|
|
10
10
|
def write(events)
|
11
11
|
events.each do |event|
|
12
|
-
@data_io.write EventSerializer.serialize(event)
|
12
|
+
@data_io.write Marshal.dump EventSerializer.serialize(event)
|
13
13
|
write_to_index @data_io.pos
|
14
14
|
end
|
15
15
|
|
data/lib/aggro/handler/query.rb
CHANGED
@@ -37,15 +37,15 @@ module Aggro
|
|
37
37
|
end
|
38
38
|
|
39
39
|
def handle_known
|
40
|
-
if channel
|
41
|
-
|
42
|
-
|
43
|
-
|
40
|
+
if channel
|
41
|
+
if channel.handles_query?(query)
|
42
|
+
handle_supported
|
43
|
+
else
|
44
|
+
Message::UnhandledOperation.new
|
45
|
+
end
|
44
46
|
else
|
45
|
-
Message::
|
47
|
+
Message::InvalidTarget.new
|
46
48
|
end
|
47
|
-
rescue NoMethodError
|
48
|
-
Message::InvalidTarget.new
|
49
49
|
end
|
50
50
|
|
51
51
|
def handle_local
|
@@ -55,6 +55,18 @@ module Aggro
|
|
55
55
|
def handle_unknown
|
56
56
|
Message::UnknownOperation.new
|
57
57
|
end
|
58
|
+
|
59
|
+
def handle_supported
|
60
|
+
result = channel.run_query(query)
|
61
|
+
|
62
|
+
result.wait(5)
|
63
|
+
|
64
|
+
if result.fulfilled?
|
65
|
+
Message::Result.new result.value
|
66
|
+
else
|
67
|
+
Message::Result.new Aggro::QueryError.new('Query timed out')
|
68
|
+
end
|
69
|
+
end
|
58
70
|
end
|
59
71
|
end
|
60
72
|
end
|