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
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
|