aggro 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|