omq 0.10.0 → 0.12.0
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/CHANGELOG.md +157 -0
- data/README.md +31 -4
- data/lib/omq/drop_queue.rb +54 -0
- data/lib/omq/engine.rb +103 -61
- data/lib/omq/monitor_event.rb +16 -0
- data/lib/omq/options.rb +6 -2
- data/lib/omq/pair.rb +2 -2
- data/lib/omq/pub_sub.rb +13 -12
- data/lib/omq/push_pull.rb +4 -4
- data/lib/omq/queue_interface.rb +73 -0
- data/lib/omq/readable.rb +2 -0
- data/lib/omq/req_rep.rb +4 -4
- data/lib/omq/router_dealer.rb +4 -4
- data/lib/omq/routing/dealer.rb +1 -1
- data/lib/omq/routing/fan_out.rb +26 -5
- data/lib/omq/routing/pair.rb +2 -2
- data/lib/omq/routing/pull.rb +1 -1
- data/lib/omq/routing/push.rb +2 -0
- data/lib/omq/routing/rep.rb +2 -2
- data/lib/omq/routing/req.rb +8 -3
- data/lib/omq/routing/round_robin.rb +4 -12
- data/lib/omq/routing/router.rb +2 -2
- data/lib/omq/routing/sub.rb +1 -2
- data/lib/omq/routing/xpub.rb +1 -1
- data/lib/omq/routing/xsub.rb +2 -2
- data/lib/omq/routing.rb +41 -11
- data/lib/omq/socket.rb +49 -2
- data/lib/omq/transport/inproc.rb +25 -7
- data/lib/omq/transport/ipc.rb +16 -4
- data/lib/omq/transport/tcp.rb +31 -8
- data/lib/omq/version.rb +1 -1
- data/lib/omq/writable.rb +1 -0
- data/lib/omq.rb +6 -16
- metadata +4 -15
- data/lib/omq/channel.rb +0 -14
- data/lib/omq/client_server.rb +0 -37
- data/lib/omq/peer.rb +0 -26
- data/lib/omq/radio_dish.rb +0 -74
- data/lib/omq/routing/channel.rb +0 -83
- data/lib/omq/routing/client.rb +0 -56
- data/lib/omq/routing/dish.rb +0 -78
- data/lib/omq/routing/gather.rb +0 -46
- data/lib/omq/routing/peer.rb +0 -101
- data/lib/omq/routing/radio.rb +0 -140
- data/lib/omq/routing/scatter.rb +0 -82
- data/lib/omq/routing/server.rb +0 -101
- data/lib/omq/scatter_gather.rb +0 -23
- data/lib/omq/single_frame.rb +0 -18
data/lib/omq/pub_sub.rb
CHANGED
|
@@ -4,8 +4,8 @@ module OMQ
|
|
|
4
4
|
class PUB < Socket
|
|
5
5
|
include Writable
|
|
6
6
|
|
|
7
|
-
def initialize(endpoints = nil, linger: 0, conflate: false)
|
|
8
|
-
_init_engine(:PUB, linger: linger, conflate: conflate)
|
|
7
|
+
def initialize(endpoints = nil, linger: 0, on_mute: :drop_newest, conflate: false, backend: nil)
|
|
8
|
+
_init_engine(:PUB, linger: linger, on_mute: on_mute, conflate: conflate, backend: backend)
|
|
9
9
|
_attach(endpoints, default: :bind)
|
|
10
10
|
end
|
|
11
11
|
end
|
|
@@ -21,13 +21,14 @@ module OMQ
|
|
|
21
21
|
|
|
22
22
|
# @param endpoints [String, nil]
|
|
23
23
|
# @param linger [Integer]
|
|
24
|
-
# @param
|
|
24
|
+
# @param subscribe [String, nil] subscription prefix; +nil+ (default)
|
|
25
25
|
# means no subscription — call {#subscribe} explicitly.
|
|
26
|
+
# @param on_mute [Symbol] :block (default), :drop_newest, or :drop_oldest
|
|
26
27
|
#
|
|
27
|
-
def initialize(endpoints = nil, linger: 0,
|
|
28
|
-
_init_engine(:SUB, linger: linger)
|
|
28
|
+
def initialize(endpoints = nil, linger: 0, subscribe: nil, on_mute: :block, backend: nil)
|
|
29
|
+
_init_engine(:SUB, linger: linger, on_mute: on_mute, backend: backend)
|
|
29
30
|
_attach(endpoints, default: :connect)
|
|
30
|
-
subscribe(
|
|
31
|
+
self.subscribe(subscribe) unless subscribe.nil?
|
|
31
32
|
end
|
|
32
33
|
|
|
33
34
|
# Subscribes to a topic prefix.
|
|
@@ -53,8 +54,8 @@ module OMQ
|
|
|
53
54
|
include Readable
|
|
54
55
|
include Writable
|
|
55
56
|
|
|
56
|
-
def initialize(endpoints = nil, linger: 0)
|
|
57
|
-
_init_engine(:XPUB, linger: linger)
|
|
57
|
+
def initialize(endpoints = nil, linger: 0, on_mute: :drop_newest, backend: nil)
|
|
58
|
+
_init_engine(:XPUB, linger: linger, on_mute: on_mute, backend: backend)
|
|
58
59
|
_attach(endpoints, default: :bind)
|
|
59
60
|
end
|
|
60
61
|
end
|
|
@@ -65,13 +66,13 @@ module OMQ
|
|
|
65
66
|
|
|
66
67
|
# @param endpoints [String, nil]
|
|
67
68
|
# @param linger [Integer]
|
|
68
|
-
# @param
|
|
69
|
+
# @param subscribe [String, nil] subscription prefix; +nil+ (default)
|
|
69
70
|
# means no subscription — send a subscribe frame explicitly.
|
|
70
71
|
#
|
|
71
|
-
def initialize(endpoints = nil, linger: 0,
|
|
72
|
-
_init_engine(:XSUB, linger: linger)
|
|
72
|
+
def initialize(endpoints = nil, linger: 0, subscribe: nil, on_mute: :block, backend: nil)
|
|
73
|
+
_init_engine(:XSUB, linger: linger, on_mute: on_mute, backend: backend)
|
|
73
74
|
_attach(endpoints, default: :connect)
|
|
74
|
-
send("\x01#{
|
|
75
|
+
send("\x01#{subscribe}".b) unless subscribe.nil?
|
|
75
76
|
end
|
|
76
77
|
end
|
|
77
78
|
end
|
data/lib/omq/push_pull.rb
CHANGED
|
@@ -4,8 +4,8 @@ module OMQ
|
|
|
4
4
|
class PUSH < Socket
|
|
5
5
|
include Writable
|
|
6
6
|
|
|
7
|
-
def initialize(endpoints = nil, linger: 0, send_hwm: nil, send_timeout: nil)
|
|
8
|
-
_init_engine(:PUSH, linger: linger, send_hwm: send_hwm, send_timeout: send_timeout)
|
|
7
|
+
def initialize(endpoints = nil, linger: 0, send_hwm: nil, send_timeout: nil, backend: nil)
|
|
8
|
+
_init_engine(:PUSH, linger: linger, send_hwm: send_hwm, send_timeout: send_timeout, backend: backend)
|
|
9
9
|
_attach(endpoints, default: :connect)
|
|
10
10
|
end
|
|
11
11
|
end
|
|
@@ -13,8 +13,8 @@ module OMQ
|
|
|
13
13
|
class PULL < Socket
|
|
14
14
|
include Readable
|
|
15
15
|
|
|
16
|
-
def initialize(endpoints = nil, linger: 0, recv_hwm: nil, recv_timeout: nil)
|
|
17
|
-
_init_engine(:PULL, linger: linger, recv_hwm: recv_hwm, recv_timeout: recv_timeout)
|
|
16
|
+
def initialize(endpoints = nil, linger: 0, recv_hwm: nil, recv_timeout: nil, backend: nil)
|
|
17
|
+
_init_engine(:PULL, linger: linger, recv_hwm: recv_hwm, recv_timeout: recv_timeout, backend: backend)
|
|
18
18
|
_attach(endpoints, default: :bind)
|
|
19
19
|
end
|
|
20
20
|
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module OMQ
|
|
4
|
+
# Async::Queue-compatible read interface.
|
|
5
|
+
#
|
|
6
|
+
# Automatically included by {Readable}. Provides #dequeue, #pop,
|
|
7
|
+
# #wait, and #each so sockets can be used where an Async::Queue
|
|
8
|
+
# is expected.
|
|
9
|
+
#
|
|
10
|
+
module QueueReadable
|
|
11
|
+
# Dequeues the next message.
|
|
12
|
+
#
|
|
13
|
+
# @param timeout [Numeric, nil] timeout in seconds (overrides
|
|
14
|
+
# the socket's +read_timeout+ for this call)
|
|
15
|
+
# @return [Array<String>] message parts
|
|
16
|
+
# @raise [IO::TimeoutError] if timeout exceeded
|
|
17
|
+
#
|
|
18
|
+
def dequeue(timeout: @options.read_timeout)
|
|
19
|
+
msg = @recv_mutex.synchronize { @recv_buffer.shift }
|
|
20
|
+
return msg if msg
|
|
21
|
+
|
|
22
|
+
batch = Reactor.run { with_timeout(timeout) { @engine.dequeue_recv_batch(Readable::RECV_BATCH_SIZE) } }
|
|
23
|
+
msg = batch.shift
|
|
24
|
+
@recv_mutex.synchronize { @recv_buffer.concat(batch) } unless batch.empty?
|
|
25
|
+
msg
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
alias_method :pop, :dequeue
|
|
29
|
+
|
|
30
|
+
# Waits for the next message indefinitely (ignores read_timeout).
|
|
31
|
+
#
|
|
32
|
+
# @return [Array<String>] message parts
|
|
33
|
+
#
|
|
34
|
+
def wait
|
|
35
|
+
dequeue(timeout: nil)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Yields each received message until the socket is closed or
|
|
39
|
+
# a receive timeout expires.
|
|
40
|
+
#
|
|
41
|
+
# @yield [Array<String>] message parts
|
|
42
|
+
# @return [void]
|
|
43
|
+
#
|
|
44
|
+
def each
|
|
45
|
+
while (msg = receive)
|
|
46
|
+
yield msg
|
|
47
|
+
end
|
|
48
|
+
rescue IO::TimeoutError
|
|
49
|
+
nil
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
# Async::Queue-compatible write interface.
|
|
55
|
+
#
|
|
56
|
+
# Automatically included by {Writable}. Provides #enqueue, #push,
|
|
57
|
+
# and #signal so sockets can be used where an Async::Queue is
|
|
58
|
+
# expected.
|
|
59
|
+
#
|
|
60
|
+
module QueueWritable
|
|
61
|
+
# Enqueues one or more messages for sending.
|
|
62
|
+
#
|
|
63
|
+
# @param messages [String, Array<String>]
|
|
64
|
+
# @return [self]
|
|
65
|
+
#
|
|
66
|
+
def enqueue(*messages)
|
|
67
|
+
messages.each { |msg| send(msg) }
|
|
68
|
+
self
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
alias_method :push, :enqueue
|
|
72
|
+
end
|
|
73
|
+
end
|
data/lib/omq/readable.rb
CHANGED
data/lib/omq/req_rep.rb
CHANGED
|
@@ -5,8 +5,8 @@ module OMQ
|
|
|
5
5
|
include Readable
|
|
6
6
|
include Writable
|
|
7
7
|
|
|
8
|
-
def initialize(endpoints = nil, linger: 0)
|
|
9
|
-
_init_engine(:REQ, linger: linger)
|
|
8
|
+
def initialize(endpoints = nil, linger: 0, backend: nil)
|
|
9
|
+
_init_engine(:REQ, linger: linger, backend: backend)
|
|
10
10
|
_attach(endpoints, default: :connect)
|
|
11
11
|
end
|
|
12
12
|
end
|
|
@@ -15,8 +15,8 @@ module OMQ
|
|
|
15
15
|
include Readable
|
|
16
16
|
include Writable
|
|
17
17
|
|
|
18
|
-
def initialize(endpoints = nil, linger: 0)
|
|
19
|
-
_init_engine(:REP, linger: linger)
|
|
18
|
+
def initialize(endpoints = nil, linger: 0, backend: nil)
|
|
19
|
+
_init_engine(:REP, linger: linger, backend: backend)
|
|
20
20
|
_attach(endpoints, default: :bind)
|
|
21
21
|
end
|
|
22
22
|
end
|
data/lib/omq/router_dealer.rb
CHANGED
|
@@ -5,8 +5,8 @@ module OMQ
|
|
|
5
5
|
include Readable
|
|
6
6
|
include Writable
|
|
7
7
|
|
|
8
|
-
def initialize(endpoints = nil, linger: 0)
|
|
9
|
-
_init_engine(:DEALER, linger: linger)
|
|
8
|
+
def initialize(endpoints = nil, linger: 0, backend: nil)
|
|
9
|
+
_init_engine(:DEALER, linger: linger, backend: backend)
|
|
10
10
|
_attach(endpoints, default: :connect)
|
|
11
11
|
end
|
|
12
12
|
end
|
|
@@ -17,8 +17,8 @@ module OMQ
|
|
|
17
17
|
include Readable
|
|
18
18
|
include Writable
|
|
19
19
|
|
|
20
|
-
def initialize(endpoints = nil, linger: 0)
|
|
21
|
-
_init_engine(:ROUTER, linger: linger)
|
|
20
|
+
def initialize(endpoints = nil, linger: 0, backend: nil)
|
|
21
|
+
_init_engine(:ROUTER, linger: linger, backend: backend)
|
|
22
22
|
_attach(endpoints, default: :bind)
|
|
23
23
|
end
|
|
24
24
|
|
data/lib/omq/routing/dealer.rb
CHANGED
data/lib/omq/routing/fan_out.rb
CHANGED
|
@@ -13,12 +13,16 @@ module OMQ
|
|
|
13
13
|
module FanOut
|
|
14
14
|
attr_reader :subscriber_joined
|
|
15
15
|
|
|
16
|
+
# @return [Boolean] true when the send pump is idle (not sending a batch)
|
|
17
|
+
def send_pump_idle? = @send_pump_idle
|
|
18
|
+
|
|
16
19
|
private
|
|
17
20
|
|
|
18
21
|
def init_fan_out(engine)
|
|
19
22
|
@connections = []
|
|
20
23
|
@subscriptions = {} # connection => Set of prefixes
|
|
21
|
-
@send_queue =
|
|
24
|
+
@send_queue = Routing.build_queue(engine.options.send_hwm, :block)
|
|
25
|
+
@on_mute = engine.options.on_mute
|
|
22
26
|
@send_pump_started = false
|
|
23
27
|
@send_pump_idle = true
|
|
24
28
|
@conflate = engine.options.conflate
|
|
@@ -57,8 +61,14 @@ module OMQ
|
|
|
57
61
|
@subscriptions[conn]&.delete(prefix)
|
|
58
62
|
end
|
|
59
63
|
|
|
60
|
-
#
|
|
61
|
-
|
|
64
|
+
# Returns true if the connection is muted (recv queue full) and
|
|
65
|
+
# the on_mute strategy says to drop rather than block.
|
|
66
|
+
#
|
|
67
|
+
def muted?(conn)
|
|
68
|
+
return false if @on_mute == :block
|
|
69
|
+
q = conn.direct_recv_queue if conn.respond_to?(:direct_recv_queue)
|
|
70
|
+
q&.respond_to?(:limited?) && q.limited?
|
|
71
|
+
end
|
|
62
72
|
|
|
63
73
|
|
|
64
74
|
def start_send_pump
|
|
@@ -83,6 +93,7 @@ module OMQ
|
|
|
83
93
|
end
|
|
84
94
|
end
|
|
85
95
|
@latest.each do |conn, parts|
|
|
96
|
+
next if muted?(conn)
|
|
86
97
|
begin
|
|
87
98
|
conn.write_message(parts)
|
|
88
99
|
@written << conn
|
|
@@ -91,11 +102,21 @@ module OMQ
|
|
|
91
102
|
end
|
|
92
103
|
else
|
|
93
104
|
batch.each do |parts|
|
|
94
|
-
topic
|
|
105
|
+
topic = parts.first || EMPTY_BINARY
|
|
106
|
+
wire_bytes = nil
|
|
107
|
+
|
|
95
108
|
@connections.each do |conn|
|
|
96
109
|
next unless subscribed?(conn, topic)
|
|
110
|
+
next if muted?(conn)
|
|
97
111
|
begin
|
|
98
|
-
conn.
|
|
112
|
+
if conn.respond_to?(:curve?) && conn.curve?
|
|
113
|
+
conn.write_message(parts)
|
|
114
|
+
elsif conn.respond_to?(:write_wire)
|
|
115
|
+
wire_bytes ||= Protocol::ZMTP::Codec::Frame.encode_message(parts)
|
|
116
|
+
conn.write_wire(wire_bytes)
|
|
117
|
+
else
|
|
118
|
+
conn.write_message(parts)
|
|
119
|
+
end
|
|
99
120
|
@written << conn
|
|
100
121
|
rescue *CONNECTION_LOST
|
|
101
122
|
end
|
data/lib/omq/routing/pair.rb
CHANGED
|
@@ -14,8 +14,8 @@ module OMQ
|
|
|
14
14
|
def initialize(engine)
|
|
15
15
|
@engine = engine
|
|
16
16
|
@connection = nil
|
|
17
|
-
@recv_queue =
|
|
18
|
-
@send_queue =
|
|
17
|
+
@recv_queue = Routing.build_queue(engine.options.recv_hwm, :block)
|
|
18
|
+
@send_queue = Routing.build_queue(engine.options.send_hwm, :block)
|
|
19
19
|
@tasks = []
|
|
20
20
|
@send_pump_idle = true
|
|
21
21
|
end
|
data/lib/omq/routing/pull.rb
CHANGED
data/lib/omq/routing/push.rb
CHANGED
data/lib/omq/routing/rep.rb
CHANGED
|
@@ -15,8 +15,8 @@ module OMQ
|
|
|
15
15
|
|
|
16
16
|
def initialize(engine)
|
|
17
17
|
@engine = engine
|
|
18
|
-
@recv_queue =
|
|
19
|
-
@send_queue =
|
|
18
|
+
@recv_queue = Routing.build_queue(engine.options.recv_hwm, :block)
|
|
19
|
+
@send_queue = Routing.build_queue(engine.options.send_hwm, :block)
|
|
20
20
|
@pending_replies = []
|
|
21
21
|
@tasks = []
|
|
22
22
|
@send_pump_started = false
|
data/lib/omq/routing/req.rb
CHANGED
|
@@ -12,9 +12,10 @@ module OMQ
|
|
|
12
12
|
# @param engine [Engine]
|
|
13
13
|
#
|
|
14
14
|
def initialize(engine)
|
|
15
|
-
@engine
|
|
16
|
-
@recv_queue
|
|
17
|
-
@tasks
|
|
15
|
+
@engine = engine
|
|
16
|
+
@recv_queue = Routing.build_queue(engine.options.recv_hwm, :block)
|
|
17
|
+
@tasks = []
|
|
18
|
+
@state = :ready # :ready or :waiting_reply
|
|
18
19
|
init_round_robin(engine)
|
|
19
20
|
end
|
|
20
21
|
|
|
@@ -22,6 +23,7 @@ module OMQ
|
|
|
22
23
|
#
|
|
23
24
|
attr_reader :recv_queue, :send_queue
|
|
24
25
|
|
|
26
|
+
|
|
25
27
|
# @param connection [Connection]
|
|
26
28
|
#
|
|
27
29
|
def connection_added(connection)
|
|
@@ -29,6 +31,7 @@ module OMQ
|
|
|
29
31
|
signal_connection_available
|
|
30
32
|
update_direct_pipe
|
|
31
33
|
task = @engine.start_recv_pump(connection, @recv_queue) do |msg|
|
|
34
|
+
@state = :ready
|
|
32
35
|
msg.first&.empty? ? msg[1..] : msg
|
|
33
36
|
end
|
|
34
37
|
@tasks << task if task
|
|
@@ -45,6 +48,8 @@ module OMQ
|
|
|
45
48
|
# @param parts [Array<String>]
|
|
46
49
|
#
|
|
47
50
|
def enqueue(parts)
|
|
51
|
+
raise SocketError, "REQ socket expects send/recv/send/recv order" unless @state == :ready
|
|
52
|
+
@state = :waiting_reply
|
|
48
53
|
enqueue_round_robin(parts)
|
|
49
54
|
end
|
|
50
55
|
|
|
@@ -12,6 +12,9 @@ module OMQ
|
|
|
12
12
|
# their #initialize.
|
|
13
13
|
#
|
|
14
14
|
module RoundRobin
|
|
15
|
+
# @return [Boolean] true when the send pump is idle (not sending a batch)
|
|
16
|
+
def send_pump_idle? = @send_pump_idle
|
|
17
|
+
|
|
15
18
|
private
|
|
16
19
|
|
|
17
20
|
|
|
@@ -23,7 +26,7 @@ module OMQ
|
|
|
23
26
|
@connections = []
|
|
24
27
|
@cycle = @connections.cycle
|
|
25
28
|
@connection_available = Async::Promise.new
|
|
26
|
-
@send_queue =
|
|
29
|
+
@send_queue = Routing.build_queue(engine.options.send_hwm, :block)
|
|
27
30
|
@send_pump_started = false
|
|
28
31
|
@send_pump_idle = true
|
|
29
32
|
@direct_pipe = nil
|
|
@@ -90,13 +93,6 @@ module OMQ
|
|
|
90
93
|
def transform_send(parts) = parts
|
|
91
94
|
|
|
92
95
|
|
|
93
|
-
# Starts the background send pump that dequeues messages
|
|
94
|
-
# and dispatches them round-robin across connections.
|
|
95
|
-
#
|
|
96
|
-
# @return [Boolean] true when the send pump is idle (not sending a batch)
|
|
97
|
-
def send_pump_idle? = @send_pump_idle
|
|
98
|
-
|
|
99
|
-
|
|
100
96
|
def start_send_pump
|
|
101
97
|
@send_pump_started = true
|
|
102
98
|
@tasks << @engine.spawn_pump_task(annotation: "send pump") do
|
|
@@ -144,14 +140,11 @@ module OMQ
|
|
|
144
140
|
@written << conn
|
|
145
141
|
rescue *CONNECTION_LOST
|
|
146
142
|
@engine.connection_lost(conn)
|
|
147
|
-
# Flush what we've written so far
|
|
148
143
|
@written.each do |c|
|
|
149
144
|
c.flush
|
|
150
145
|
rescue *CONNECTION_LOST
|
|
151
|
-
# will be cleaned up
|
|
152
146
|
end
|
|
153
147
|
@written.clear
|
|
154
|
-
# Fall back to send_with_retry for this and remaining
|
|
155
148
|
send_with_retry(parts)
|
|
156
149
|
batch[(i + 1)..].each { |p| send_with_retry(p) }
|
|
157
150
|
return
|
|
@@ -160,7 +153,6 @@ module OMQ
|
|
|
160
153
|
@written.each do |conn|
|
|
161
154
|
conn.flush
|
|
162
155
|
rescue *CONNECTION_LOST
|
|
163
|
-
# will be cleaned up
|
|
164
156
|
end
|
|
165
157
|
end
|
|
166
158
|
end
|
data/lib/omq/routing/router.rb
CHANGED
|
@@ -15,8 +15,8 @@ module OMQ
|
|
|
15
15
|
#
|
|
16
16
|
def initialize(engine)
|
|
17
17
|
@engine = engine
|
|
18
|
-
@recv_queue =
|
|
19
|
-
@send_queue =
|
|
18
|
+
@recv_queue = Routing.build_queue(engine.options.recv_hwm, :block)
|
|
19
|
+
@send_queue = Routing.build_queue(engine.options.send_hwm, :block)
|
|
20
20
|
@connections_by_identity = {}
|
|
21
21
|
@identity_by_connection = {}
|
|
22
22
|
@tasks = []
|
data/lib/omq/routing/sub.rb
CHANGED
|
@@ -13,7 +13,7 @@ module OMQ
|
|
|
13
13
|
def initialize(engine)
|
|
14
14
|
@engine = engine
|
|
15
15
|
@connections = []
|
|
16
|
-
@recv_queue =
|
|
16
|
+
@recv_queue = Routing.build_queue(engine.options.recv_hwm, engine.options.on_mute)
|
|
17
17
|
@subscriptions = Set.new
|
|
18
18
|
@tasks = []
|
|
19
19
|
end
|
|
@@ -26,7 +26,6 @@ module OMQ
|
|
|
26
26
|
#
|
|
27
27
|
def connection_added(connection)
|
|
28
28
|
@connections << connection
|
|
29
|
-
# Send existing subscriptions to new peer
|
|
30
29
|
@subscriptions.each do |prefix|
|
|
31
30
|
connection.send_command(Protocol::ZMTP::Codec::Command.subscribe(prefix))
|
|
32
31
|
end
|
data/lib/omq/routing/xpub.rb
CHANGED
data/lib/omq/routing/xsub.rb
CHANGED
|
@@ -14,8 +14,8 @@ module OMQ
|
|
|
14
14
|
def initialize(engine)
|
|
15
15
|
@engine = engine
|
|
16
16
|
@connections = []
|
|
17
|
-
@recv_queue =
|
|
18
|
-
@send_queue =
|
|
17
|
+
@recv_queue = Routing.build_queue(engine.options.recv_hwm, engine.options.on_mute)
|
|
18
|
+
@send_queue = Routing.build_queue(engine.options.send_hwm, :block)
|
|
19
19
|
@tasks = []
|
|
20
20
|
@send_pump_started = false
|
|
21
21
|
@send_pump_idle = true
|
data/lib/omq/routing.rb
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require "async"
|
|
4
4
|
require "async/queue"
|
|
5
5
|
require "async/limited_queue"
|
|
6
|
+
require_relative "drop_queue"
|
|
6
7
|
|
|
7
8
|
module OMQ
|
|
8
9
|
# Routing strategies for each ZMQ socket type.
|
|
@@ -14,6 +15,42 @@ module OMQ
|
|
|
14
15
|
# Shared frozen empty binary string to avoid repeated allocations.
|
|
15
16
|
EMPTY_BINARY = "".b.freeze
|
|
16
17
|
|
|
18
|
+
# Plugin registry for socket types not built into omq.
|
|
19
|
+
# Populated by sister gems via +Routing.register+.
|
|
20
|
+
#
|
|
21
|
+
@registry = {}
|
|
22
|
+
|
|
23
|
+
class << self
|
|
24
|
+
# Registers a routing strategy class for a socket type.
|
|
25
|
+
# Called by omq-draft (and other plugins) at require time.
|
|
26
|
+
#
|
|
27
|
+
# @param socket_type [Symbol] e.g. :RADIO, :CLIENT
|
|
28
|
+
# @param strategy_class [Class]
|
|
29
|
+
#
|
|
30
|
+
def register(socket_type, strategy_class)
|
|
31
|
+
@registry[socket_type] = strategy_class
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Builds a send or recv queue based on the mute strategy.
|
|
36
|
+
#
|
|
37
|
+
# @param hwm [Integer] high water mark
|
|
38
|
+
# @param on_mute [Symbol] :block, :drop_newest, or :drop_oldest
|
|
39
|
+
# @return [Async::LimitedQueue, DropQueue]
|
|
40
|
+
#
|
|
41
|
+
def self.build_queue(hwm, on_mute)
|
|
42
|
+
return Async::Queue.new if hwm.nil? || hwm == 0
|
|
43
|
+
|
|
44
|
+
case on_mute
|
|
45
|
+
when :block
|
|
46
|
+
Async::LimitedQueue.new(hwm)
|
|
47
|
+
when :drop_newest, :drop_oldest
|
|
48
|
+
DropQueue.new(hwm, strategy: on_mute)
|
|
49
|
+
else
|
|
50
|
+
raise ArgumentError, "unknown on_mute strategy: #{on_mute.inspect}"
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
17
54
|
# Drains all available messages from +queue+ into +batch+ without
|
|
18
55
|
# blocking. Call after the initial blocking dequeue.
|
|
19
56
|
#
|
|
@@ -49,17 +86,10 @@ module OMQ
|
|
|
49
86
|
when :SUB then Sub
|
|
50
87
|
when :XPUB then XPub
|
|
51
88
|
when :XSUB then XSub
|
|
52
|
-
when :PUSH
|
|
53
|
-
when :PULL
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
when :RADIO then Radio
|
|
57
|
-
when :DISH then Dish
|
|
58
|
-
when :SCATTER then Scatter
|
|
59
|
-
when :GATHER then Gather
|
|
60
|
-
when :PEER then Peer
|
|
61
|
-
when :CHANNEL then Channel
|
|
62
|
-
else raise ArgumentError, "unknown socket type: #{socket_type}"
|
|
89
|
+
when :PUSH then Push
|
|
90
|
+
when :PULL then Pull
|
|
91
|
+
else
|
|
92
|
+
@registry[socket_type] or raise ArgumentError, "unknown socket type: #{socket_type.inspect}"
|
|
63
93
|
end
|
|
64
94
|
end
|
|
65
95
|
end
|
data/lib/omq/socket.rb
CHANGED
|
@@ -36,6 +36,7 @@ module OMQ
|
|
|
36
36
|
:heartbeat_ttl, :heartbeat_ttl=,
|
|
37
37
|
:heartbeat_timeout, :heartbeat_timeout=,
|
|
38
38
|
:max_message_size, :max_message_size=,
|
|
39
|
+
:on_mute, :on_mute=,
|
|
39
40
|
:mechanism, :mechanism=
|
|
40
41
|
|
|
41
42
|
|
|
@@ -140,6 +141,46 @@ module OMQ
|
|
|
140
141
|
end
|
|
141
142
|
|
|
142
143
|
|
|
144
|
+
# Yields lifecycle events for this socket.
|
|
145
|
+
#
|
|
146
|
+
# Spawns a background fiber that reads from an internal event queue.
|
|
147
|
+
# The block receives {MonitorEvent} instances until the socket is
|
|
148
|
+
# closed or the returned task is stopped.
|
|
149
|
+
#
|
|
150
|
+
# @yield [event] called for each lifecycle event
|
|
151
|
+
# @yieldparam event [MonitorEvent]
|
|
152
|
+
# @return [Async::Task] the monitor task (call +#stop+ to end early)
|
|
153
|
+
#
|
|
154
|
+
# @example
|
|
155
|
+
# task = socket.monitor do |event|
|
|
156
|
+
# case event
|
|
157
|
+
# in type: :connected, endpoint:
|
|
158
|
+
# puts "peer up: #{endpoint}"
|
|
159
|
+
# in type: :disconnected, endpoint:
|
|
160
|
+
# puts "peer down: #{endpoint}"
|
|
161
|
+
# end
|
|
162
|
+
# end
|
|
163
|
+
# # later:
|
|
164
|
+
# task.stop
|
|
165
|
+
#
|
|
166
|
+
def monitor(&block)
|
|
167
|
+
ensure_parent_task
|
|
168
|
+
queue = Async::Queue.new
|
|
169
|
+
@engine.monitor_queue = queue
|
|
170
|
+
Reactor.run do
|
|
171
|
+
@engine.parent_task.async(transient: true, annotation: "monitor") do
|
|
172
|
+
while (event = queue.dequeue)
|
|
173
|
+
block.call(event)
|
|
174
|
+
end
|
|
175
|
+
rescue Async::Stop
|
|
176
|
+
ensure
|
|
177
|
+
@engine.monitor_queue = nil
|
|
178
|
+
block.call(MonitorEvent.new(type: :monitor_stopped))
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
|
|
143
184
|
# Disable auto-reconnect for connected endpoints.
|
|
144
185
|
def reconnect_enabled=(val)
|
|
145
186
|
@engine.reconnect_enabled = val
|
|
@@ -224,16 +265,22 @@ module OMQ
|
|
|
224
265
|
# @param linger [Integer]
|
|
225
266
|
#
|
|
226
267
|
def _init_engine(socket_type, linger:, send_hwm: nil, recv_hwm: nil,
|
|
227
|
-
send_timeout: nil, recv_timeout: nil, conflate: false
|
|
268
|
+
send_timeout: nil, recv_timeout: nil, conflate: false,
|
|
269
|
+
on_mute: nil, backend: nil)
|
|
228
270
|
@options = Options.new(linger: linger)
|
|
229
271
|
@options.send_hwm = send_hwm if send_hwm
|
|
230
272
|
@options.recv_hwm = recv_hwm if recv_hwm
|
|
231
273
|
@options.send_timeout = send_timeout if send_timeout
|
|
232
274
|
@options.recv_timeout = recv_timeout if recv_timeout
|
|
233
275
|
@options.conflate = conflate
|
|
276
|
+
@options.on_mute = on_mute if on_mute
|
|
234
277
|
@recv_buffer = []
|
|
235
278
|
@recv_mutex = Mutex.new
|
|
236
|
-
@engine =
|
|
279
|
+
@engine = case backend
|
|
280
|
+
when nil, :ruby then Engine.new(socket_type, @options)
|
|
281
|
+
when :ffi then FFI::Engine.new(socket_type, @options)
|
|
282
|
+
else raise ArgumentError, "unknown backend: #{backend}"
|
|
283
|
+
end
|
|
237
284
|
end
|
|
238
285
|
end
|
|
239
286
|
end
|