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
data/lib/aggro/abstract_store.rb
DELETED
@@ -1,98 +0,0 @@
|
|
1
|
-
require 'ffi'
|
2
|
-
require 'nn-core'
|
3
|
-
require 'aggro/nanomsg_transport/socket_error'
|
4
|
-
|
5
|
-
module Aggro
|
6
|
-
module NanomsgTransport
|
7
|
-
# Private: Base class for nanomsg socket wrappers.
|
8
|
-
class Connection
|
9
|
-
attr_reader :socket
|
10
|
-
|
11
|
-
def initialize(endpoint)
|
12
|
-
@endpoint = endpoint
|
13
|
-
@rcv_buffer = FFI::MemoryPointer.new(:pointer)
|
14
|
-
|
15
|
-
allocate_socket
|
16
|
-
setup_socket
|
17
|
-
set_endpoint
|
18
|
-
end
|
19
|
-
|
20
|
-
def setup_socket
|
21
|
-
set_socket_option NNCore::NN_LINGER, 100
|
22
|
-
set_socket_option NNCore::NN_SNDBUF, 131_072
|
23
|
-
set_socket_option NNCore::NN_RCVBUF, 131_072
|
24
|
-
end
|
25
|
-
|
26
|
-
def send_msg(stringable)
|
27
|
-
msg = stringable.to_s
|
28
|
-
nbytes = NNCore::LibNanomsg.nn_send(@socket, msg, msg.bytesize, 0)
|
29
|
-
assert(nbytes)
|
30
|
-
|
31
|
-
nbytes
|
32
|
-
end
|
33
|
-
|
34
|
-
def recv_fd
|
35
|
-
get_socket_option NNCore::NN_RCVFD
|
36
|
-
end
|
37
|
-
|
38
|
-
def recv_msg
|
39
|
-
nbytes = NNCore::LibNanomsg.nn_recv(@socket, @rcv_buffer,
|
40
|
-
NNCore::NN_MSG, 0)
|
41
|
-
|
42
|
-
assert(nbytes)
|
43
|
-
|
44
|
-
str = @rcv_buffer.read_pointer
|
45
|
-
response = str.read_string(nbytes)
|
46
|
-
NNCore::LibNanomsg.nn_freemsg str
|
47
|
-
|
48
|
-
response
|
49
|
-
rescue SocketError => e
|
50
|
-
raise e unless e.errno == NNCore::EAGAIN
|
51
|
-
|
52
|
-
nil
|
53
|
-
end
|
54
|
-
|
55
|
-
def terminate
|
56
|
-
assert NNCore::LibNanomsg.nn_close(@socket)
|
57
|
-
end
|
58
|
-
|
59
|
-
protected
|
60
|
-
|
61
|
-
def assert(rc)
|
62
|
-
fail SocketError.new NNCore::LibNanomsg.nn_errno unless rc >= 0
|
63
|
-
end
|
64
|
-
|
65
|
-
def get_socket_option(setting, level = NNCore::NN_SOL_SOCKET)
|
66
|
-
result = FFI::MemoryPointer.new(:int32)
|
67
|
-
size = FFI::MemoryPointer.new(:size_t)
|
68
|
-
size.write_int result.size
|
69
|
-
|
70
|
-
rc = NNCore::LibNanomsg.nn_getsockopt(@socket, level, setting,
|
71
|
-
result, size)
|
72
|
-
|
73
|
-
assert(rc)
|
74
|
-
|
75
|
-
result.read_int
|
76
|
-
end
|
77
|
-
|
78
|
-
def prepare_socket_option(value)
|
79
|
-
if value.is_a? String
|
80
|
-
[value, value.bytesize]
|
81
|
-
else
|
82
|
-
option = FFI::MemoryPointer.new(:int32)
|
83
|
-
option.write_int(value)
|
84
|
-
|
85
|
-
[option, 4]
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
def set_socket_option(setting, value, level = NNCore::NN_SOL_SOCKET)
|
90
|
-
option, option_length = prepare_socket_option(value)
|
91
|
-
|
92
|
-
rc = NNCore::LibNanomsg.nn_setsockopt(@socket, level, setting,
|
93
|
-
option, option_length)
|
94
|
-
assert(rc)
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
require 'aggro/nanomsg_transport/connection'
|
2
|
-
|
3
|
-
module Aggro
|
4
|
-
module NanomsgTransport
|
5
|
-
# Private: Wrapper for a nanomsg PUB node.
|
6
|
-
class Publish < Connection
|
7
|
-
def allocate_socket
|
8
|
-
@socket = NNCore::LibNanomsg.nn_socket(NNCore::AF_SP, NNCore::NN_PUB)
|
9
|
-
assert @socket
|
10
|
-
end
|
11
|
-
|
12
|
-
def set_endpoint
|
13
|
-
assert NNCore::LibNanomsg.nn_bind(@socket, @endpoint)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
@@ -1,18 +0,0 @@
|
|
1
|
-
require 'aggro/nanomsg_transport/connection'
|
2
|
-
|
3
|
-
module Aggro
|
4
|
-
module NanomsgTransport
|
5
|
-
# Private: Wrapper for a nanomsg XREP node.
|
6
|
-
class RawReply < Connection
|
7
|
-
def allocate_socket
|
8
|
-
@socket = NNCore::LibNanomsg.nn_socket(NNCore::AF_SP_RAW,
|
9
|
-
NNCore::NN_REP)
|
10
|
-
assert @socket
|
11
|
-
end
|
12
|
-
|
13
|
-
def set_endpoint
|
14
|
-
assert NNCore::LibNanomsg.nn_bind(@socket, @endpoint)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
@@ -1,18 +0,0 @@
|
|
1
|
-
require 'aggro/nanomsg_transport/connection'
|
2
|
-
|
3
|
-
module Aggro
|
4
|
-
module NanomsgTransport
|
5
|
-
# Private: Wrapper for a nanomsg XREQ node.
|
6
|
-
class RawRequest < Connection
|
7
|
-
def allocate_socket
|
8
|
-
@socket = NNCore::LibNanomsg.nn_socket(NNCore::AF_SP_RAW,
|
9
|
-
NNCore::NN_REQ)
|
10
|
-
assert @socket
|
11
|
-
end
|
12
|
-
|
13
|
-
def set_endpoint
|
14
|
-
assert NNCore::LibNanomsg.nn_bind(@socket, @endpoint)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
require 'aggro/nanomsg_transport/connection'
|
2
|
-
|
3
|
-
module Aggro
|
4
|
-
module NanomsgTransport
|
5
|
-
# Private: Wrapper for a nanomsg REP node.
|
6
|
-
class Reply < Connection
|
7
|
-
def allocate_socket
|
8
|
-
@socket = NNCore::LibNanomsg.nn_socket(NNCore::AF_SP, NNCore::NN_REP)
|
9
|
-
assert @socket
|
10
|
-
end
|
11
|
-
|
12
|
-
def set_endpoint
|
13
|
-
assert NNCore::LibNanomsg.nn_connect(@socket, @endpoint)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
require 'aggro/nanomsg_transport/connection'
|
2
|
-
|
3
|
-
module Aggro
|
4
|
-
module NanomsgTransport
|
5
|
-
# Private: Wrapper for a nanomsg REQ node.
|
6
|
-
class Request < Connection
|
7
|
-
def allocate_socket
|
8
|
-
@socket = NNCore::LibNanomsg.nn_socket(NNCore::AF_SP, NNCore::NN_REQ)
|
9
|
-
assert @socket
|
10
|
-
end
|
11
|
-
|
12
|
-
def set_endpoint
|
13
|
-
assert NNCore::LibNanomsg.nn_connect(@socket, @endpoint)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
@@ -1,84 +0,0 @@
|
|
1
|
-
require 'nio'
|
2
|
-
|
3
|
-
require 'aggro/nanomsg_transport/raw_reply'
|
4
|
-
require 'aggro/nanomsg_transport/raw_request'
|
5
|
-
require 'aggro/nanomsg_transport/reply'
|
6
|
-
|
7
|
-
module Aggro
|
8
|
-
module NanomsgTransport
|
9
|
-
# Public: Server to handle messages from nanomsg clients.
|
10
|
-
class Server
|
11
|
-
DEFAULT_WORKER_COUNT = 16
|
12
|
-
|
13
|
-
class ServerAlreadyRunning < RuntimeError; end
|
14
|
-
|
15
|
-
def initialize(endpoint, callable = nil, &block)
|
16
|
-
fail ArgumentError unless callable || block_given?
|
17
|
-
|
18
|
-
@callable = block_given? ? block : callable
|
19
|
-
@endpoint = endpoint
|
20
|
-
@selectors = DEFAULT_WORKER_COUNT.times.map { NIO::Selector.new }
|
21
|
-
@inproc_endpoint = "inproc://aggro-server-#{SecureRandom.hex}"
|
22
|
-
|
23
|
-
ObjectSpace.define_finalizer self, method(:stop)
|
24
|
-
end
|
25
|
-
|
26
|
-
def start
|
27
|
-
fail ServerAlreadyRunning if @running
|
28
|
-
|
29
|
-
@running = true
|
30
|
-
start_master
|
31
|
-
DEFAULT_WORKER_COUNT.times { |i| start_worker i }
|
32
|
-
|
33
|
-
sleep 0.01 while @selectors.any?(&:empty?)
|
34
|
-
|
35
|
-
self
|
36
|
-
end
|
37
|
-
|
38
|
-
def stop
|
39
|
-
return self unless @running
|
40
|
-
|
41
|
-
@running = false
|
42
|
-
@selectors.each(&:wakeup)
|
43
|
-
|
44
|
-
sleep 0.01 until @selectors.any?(&:empty?)
|
45
|
-
|
46
|
-
@raw_reply.terminate
|
47
|
-
@raw_request.terminate
|
48
|
-
|
49
|
-
self
|
50
|
-
end
|
51
|
-
|
52
|
-
private
|
53
|
-
|
54
|
-
def handle_request(socket)
|
55
|
-
message = socket.recv_msg
|
56
|
-
socket.send_msg @callable.call(message) if @running
|
57
|
-
end
|
58
|
-
|
59
|
-
def start_master
|
60
|
-
@master_thread = Concurrent::SingleThreadExecutor.new.post do
|
61
|
-
@raw_reply = RawReply.new(@endpoint)
|
62
|
-
@raw_request = RawRequest.new(@inproc_endpoint)
|
63
|
-
|
64
|
-
NNCore::LibNanomsg.nn_device @raw_request.socket, @raw_reply.socket
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
def start_worker(i)
|
69
|
-
Concurrent::SingleThreadExecutor.new.post do
|
70
|
-
reply = Reply.new(@inproc_endpoint)
|
71
|
-
io = IO.new(reply.recv_fd, 'rb', autoclose: false)
|
72
|
-
|
73
|
-
@selectors[i].register io, :r
|
74
|
-
|
75
|
-
@selectors[i].select { handle_request(reply) } while @running
|
76
|
-
|
77
|
-
@selectors[i].deregister io
|
78
|
-
io.close
|
79
|
-
reply.terminate
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
@@ -1,20 +0,0 @@
|
|
1
|
-
module Aggro
|
2
|
-
module NanomsgTransport
|
3
|
-
# Public: An error calling the nanomsg API.
|
4
|
-
class SocketError < RuntimeError
|
5
|
-
attr_reader :errno
|
6
|
-
|
7
|
-
def initialize(errno)
|
8
|
-
@errno = errno
|
9
|
-
end
|
10
|
-
|
11
|
-
def error_message
|
12
|
-
NNCore::LibNanomsg.nn_strerror(errno)
|
13
|
-
end
|
14
|
-
|
15
|
-
def to_s
|
16
|
-
"Last nanomsg API call failed with '#{error_message}'"
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
@@ -1,27 +0,0 @@
|
|
1
|
-
require 'aggro/nanomsg_transport/connection'
|
2
|
-
|
3
|
-
module Aggro
|
4
|
-
module NanomsgTransport
|
5
|
-
# Private: Wrapper for a nanomsg SUB node.
|
6
|
-
class Subscribe < Connection
|
7
|
-
def add_subscription(topic)
|
8
|
-
set_socket_option NNCore::NN_SUB_SUBSCRIBE, topic, NNCore::NN_SUB
|
9
|
-
end
|
10
|
-
|
11
|
-
def allocate_socket
|
12
|
-
@socket = NNCore::LibNanomsg.nn_socket(NNCore::AF_SP, NNCore::NN_SUB)
|
13
|
-
assert @socket
|
14
|
-
end
|
15
|
-
|
16
|
-
def set_endpoint
|
17
|
-
assert NNCore::LibNanomsg.nn_connect(@socket, @endpoint)
|
18
|
-
end
|
19
|
-
|
20
|
-
def setup_socket
|
21
|
-
super
|
22
|
-
|
23
|
-
set_socket_option NNCore::NN_RCVTIMEO, 100
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
@@ -1,15 +0,0 @@
|
|
1
|
-
RSpec.describe AbstractStore do
|
2
|
-
subject(:store) { AbstractStore.new }
|
3
|
-
|
4
|
-
describe '#read' do
|
5
|
-
it 'should raise not implemented error' do
|
6
|
-
expect { store.read(double) }.to raise_error NotImplementedError
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
|
-
describe '#write' do
|
11
|
-
it 'should raise not implemented error' do
|
12
|
-
expect { store.write(double) }.to raise_error NotImplementedError
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
@@ -1,21 +0,0 @@
|
|
1
|
-
RSpec.describe NanomsgTransport::SocketError do
|
2
|
-
subject(:error) { NanomsgTransport::SocketError.new 5 }
|
3
|
-
|
4
|
-
let(:nanomsg_api) { spy nn_strerror: 'No u' }
|
5
|
-
|
6
|
-
before do
|
7
|
-
stub_const 'NNCore::LibNanomsg', nanomsg_api
|
8
|
-
end
|
9
|
-
|
10
|
-
describe '#to_s' do
|
11
|
-
it 'should ask nanomsg for the meaning of the errno' do
|
12
|
-
error.to_s
|
13
|
-
|
14
|
-
expect(nanomsg_api).to have_received(:nn_strerror).with 5
|
15
|
-
end
|
16
|
-
|
17
|
-
it 'should provide a human readable error message' do
|
18
|
-
expect(error.to_s).to eq "Last nanomsg API call failed with 'No u'"
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|