omq 0.22.1 → 0.24.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 +162 -0
- data/README.md +17 -21
- data/lib/omq/channel.rb +35 -0
- data/lib/omq/client_server.rb +72 -0
- data/lib/omq/constants.rb +68 -0
- data/lib/omq/engine/connection_lifecycle.rb +22 -8
- data/lib/omq/engine/heartbeat.rb +3 -4
- data/lib/omq/engine/maintenance.rb +4 -5
- data/lib/omq/engine/reconnect.rb +12 -11
- data/lib/omq/engine/recv_pump.rb +10 -10
- data/lib/omq/engine/socket_lifecycle.rb +26 -9
- data/lib/omq/engine.rb +202 -90
- data/lib/omq/peer.rb +49 -0
- data/lib/omq/pub_sub.rb +2 -2
- data/lib/omq/radio_dish.rb +122 -0
- data/lib/omq/reactor.rb +14 -5
- data/lib/omq/readable.rb +5 -1
- data/lib/omq/routing/channel.rb +110 -0
- data/lib/omq/routing/client.rb +70 -0
- data/lib/omq/routing/conn_send_pump.rb +5 -8
- data/lib/omq/routing/dealer.rb +3 -15
- data/lib/omq/routing/dish.rb +94 -0
- data/lib/omq/routing/fan_out.rb +12 -16
- data/lib/omq/routing/gather.rb +60 -0
- data/lib/omq/routing/pair.rb +7 -26
- data/lib/omq/routing/peer.rb +95 -0
- data/lib/omq/routing/pub.rb +2 -13
- data/lib/omq/routing/pull.rb +3 -15
- data/lib/omq/routing/push.rb +4 -13
- data/lib/omq/routing/radio.rb +187 -0
- data/lib/omq/routing/rep.rb +5 -19
- data/lib/omq/routing/req.rb +6 -18
- data/lib/omq/routing/round_robin.rb +15 -19
- data/lib/omq/routing/router.rb +5 -19
- data/lib/omq/routing/scatter.rb +76 -0
- data/lib/omq/routing/server.rb +90 -0
- data/lib/omq/routing/sub.rb +3 -15
- data/lib/omq/routing/xpub.rb +2 -13
- data/lib/omq/routing/xsub.rb +8 -25
- data/lib/omq/scatter_gather.rb +56 -0
- data/lib/omq/socket.rb +8 -23
- data/lib/omq/transport/inproc/{direct_pipe.rb → pipe.rb} +26 -24
- data/lib/omq/transport/inproc.rb +22 -14
- data/lib/omq/transport/ipc.rb +41 -13
- data/lib/omq/transport/tcp.rb +59 -23
- data/lib/omq/transport/udp.rb +281 -0
- data/lib/omq/version.rb +1 -1
- data/lib/omq/writable.rb +11 -42
- data/lib/omq.rb +9 -64
- metadata +17 -3
- data/lib/omq/monitor_event.rb +0 -16
data/lib/omq/routing/pair.rb
CHANGED
|
@@ -22,8 +22,6 @@ module OMQ
|
|
|
22
22
|
@connection = nil
|
|
23
23
|
@recv_queue = Routing.build_queue(engine.options.recv_hwm, :block)
|
|
24
24
|
@send_queue = Routing.build_queue(engine.options.send_hwm, :block)
|
|
25
|
-
@send_pump = nil
|
|
26
|
-
@tasks = []
|
|
27
25
|
end
|
|
28
26
|
|
|
29
27
|
|
|
@@ -45,30 +43,25 @@ module OMQ
|
|
|
45
43
|
end
|
|
46
44
|
|
|
47
45
|
|
|
48
|
-
# @param connection [Connection]
|
|
46
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
49
47
|
# @raise [RuntimeError] if a connection already exists
|
|
50
48
|
#
|
|
51
49
|
def connection_added(connection)
|
|
52
50
|
raise "PAIR allows only one peer" if @connection
|
|
53
51
|
@connection = connection
|
|
54
52
|
|
|
55
|
-
|
|
56
|
-
@tasks << task if task
|
|
53
|
+
@engine.start_recv_pump(connection, @recv_queue)
|
|
57
54
|
|
|
58
|
-
unless connection.is_a?(Transport::Inproc::
|
|
55
|
+
unless connection.is_a?(Transport::Inproc::Pipe)
|
|
59
56
|
start_send_pump(connection)
|
|
60
57
|
end
|
|
61
58
|
end
|
|
62
59
|
|
|
63
60
|
|
|
64
|
-
# @param connection [Connection]
|
|
61
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
65
62
|
#
|
|
66
63
|
def connection_removed(connection)
|
|
67
|
-
if @connection == connection
|
|
68
|
-
@connection = nil
|
|
69
|
-
@send_pump&.stop
|
|
70
|
-
@send_pump = nil
|
|
71
|
-
end
|
|
64
|
+
@connection = nil if @connection == connection
|
|
72
65
|
end
|
|
73
66
|
|
|
74
67
|
|
|
@@ -76,7 +69,7 @@ module OMQ
|
|
|
76
69
|
#
|
|
77
70
|
def enqueue(parts)
|
|
78
71
|
conn = @connection
|
|
79
|
-
if conn.is_a?(Transport::Inproc::
|
|
72
|
+
if conn.is_a?(Transport::Inproc::Pipe) && conn.direct_recv_queue
|
|
80
73
|
conn.send_message(parts)
|
|
81
74
|
else
|
|
82
75
|
@send_queue.enqueue(parts)
|
|
@@ -84,16 +77,6 @@ module OMQ
|
|
|
84
77
|
end
|
|
85
78
|
|
|
86
79
|
|
|
87
|
-
# Stops all background tasks.
|
|
88
|
-
#
|
|
89
|
-
# @return [void]
|
|
90
|
-
#
|
|
91
|
-
def stop
|
|
92
|
-
@tasks.each(&:stop)
|
|
93
|
-
@tasks.clear
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
|
|
97
80
|
# @return [Boolean] true when the shared send queue is empty
|
|
98
81
|
#
|
|
99
82
|
def send_queues_drained?
|
|
@@ -105,7 +88,7 @@ module OMQ
|
|
|
105
88
|
|
|
106
89
|
|
|
107
90
|
def start_send_pump(conn)
|
|
108
|
-
@
|
|
91
|
+
@engine.spawn_conn_pump_task(conn, annotation: "send pump") do
|
|
109
92
|
batch = []
|
|
110
93
|
|
|
111
94
|
loop do
|
|
@@ -124,8 +107,6 @@ module OMQ
|
|
|
124
107
|
batch.clear
|
|
125
108
|
end
|
|
126
109
|
end
|
|
127
|
-
|
|
128
|
-
@tasks << @send_pump
|
|
129
110
|
end
|
|
130
111
|
|
|
131
112
|
end
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "securerandom"
|
|
4
|
+
|
|
5
|
+
module OMQ
|
|
6
|
+
module Routing
|
|
7
|
+
# PEER socket routing: bidirectional multi-peer with auto-generated
|
|
8
|
+
# 4-byte routing IDs.
|
|
9
|
+
#
|
|
10
|
+
# Prepends routing ID on receive. Strips routing ID on send and
|
|
11
|
+
# routes to the identified connection.
|
|
12
|
+
#
|
|
13
|
+
class Peer
|
|
14
|
+
# @return [Async::LimitedQueue]
|
|
15
|
+
#
|
|
16
|
+
attr_reader :recv_queue
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# @return [Hash{String => Connection}] routing_id → connection
|
|
20
|
+
#
|
|
21
|
+
attr_reader :connections_by_routing_id
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# @param engine [Engine]
|
|
25
|
+
#
|
|
26
|
+
def initialize(engine)
|
|
27
|
+
@engine = engine
|
|
28
|
+
@recv_queue = Routing.build_queue(engine.options.recv_hwm, :block)
|
|
29
|
+
@connections_by_routing_id = {}
|
|
30
|
+
@routing_id_by_connection = {}
|
|
31
|
+
@conn_queues = {}
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
# Dequeues the next received message. Blocks until one is available.
|
|
36
|
+
#
|
|
37
|
+
# @return [Array<String>, nil]
|
|
38
|
+
#
|
|
39
|
+
def dequeue_recv
|
|
40
|
+
@recv_queue.dequeue
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
# Wakes a blocked {#dequeue_recv} with a nil sentinel.
|
|
45
|
+
#
|
|
46
|
+
# @return [void]
|
|
47
|
+
#
|
|
48
|
+
def unblock_recv
|
|
49
|
+
@recv_queue.enqueue(nil)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
54
|
+
#
|
|
55
|
+
def connection_added(connection)
|
|
56
|
+
routing_id = SecureRandom.bytes(4)
|
|
57
|
+
@connections_by_routing_id[routing_id] = connection
|
|
58
|
+
@routing_id_by_connection[connection] = routing_id
|
|
59
|
+
|
|
60
|
+
@engine.start_recv_pump(connection, @recv_queue) { |msg| [routing_id, *msg] }
|
|
61
|
+
|
|
62
|
+
q = Routing.build_queue(@engine.options.send_hwm, :block)
|
|
63
|
+
@conn_queues[connection] = q
|
|
64
|
+
ConnSendPump.start(@engine, connection, q)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
69
|
+
#
|
|
70
|
+
def connection_removed(connection)
|
|
71
|
+
routing_id = @routing_id_by_connection.delete(connection)
|
|
72
|
+
@connections_by_routing_id.delete(routing_id) if routing_id
|
|
73
|
+
@conn_queues.delete(connection)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
# @param parts [Array<String>]
|
|
78
|
+
#
|
|
79
|
+
def enqueue(parts)
|
|
80
|
+
routing_id = parts.first
|
|
81
|
+
conn = @connections_by_routing_id[routing_id]
|
|
82
|
+
return unless conn
|
|
83
|
+
@conn_queues[conn]&.enqueue(parts[1..])
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
# True when all per-connection send queues are empty.
|
|
88
|
+
#
|
|
89
|
+
def send_queues_drained?
|
|
90
|
+
@conn_queues.values.all?(&:empty?)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
data/lib/omq/routing/pub.rb
CHANGED
|
@@ -15,7 +15,6 @@ module OMQ
|
|
|
15
15
|
#
|
|
16
16
|
def initialize(engine)
|
|
17
17
|
@engine = engine
|
|
18
|
-
@tasks = []
|
|
19
18
|
init_fan_out(engine)
|
|
20
19
|
end
|
|
21
20
|
|
|
@@ -37,7 +36,7 @@ module OMQ
|
|
|
37
36
|
end
|
|
38
37
|
|
|
39
38
|
|
|
40
|
-
# @param connection [Connection]
|
|
39
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
41
40
|
#
|
|
42
41
|
def connection_added(connection)
|
|
43
42
|
@connections << connection
|
|
@@ -47,7 +46,7 @@ module OMQ
|
|
|
47
46
|
end
|
|
48
47
|
|
|
49
48
|
|
|
50
|
-
# @param connection [Connection]
|
|
49
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
51
50
|
#
|
|
52
51
|
def connection_removed(connection)
|
|
53
52
|
@connections.delete(connection)
|
|
@@ -62,16 +61,6 @@ module OMQ
|
|
|
62
61
|
fan_out_enqueue(parts)
|
|
63
62
|
end
|
|
64
63
|
|
|
65
|
-
|
|
66
|
-
# Stops all background tasks.
|
|
67
|
-
#
|
|
68
|
-
# @return [void]
|
|
69
|
-
#
|
|
70
|
-
def stop
|
|
71
|
-
@tasks.each(&:stop)
|
|
72
|
-
@tasks.clear
|
|
73
|
-
end
|
|
74
|
-
|
|
75
64
|
end
|
|
76
65
|
end
|
|
77
66
|
end
|
data/lib/omq/routing/pull.rb
CHANGED
|
@@ -10,7 +10,6 @@ module OMQ
|
|
|
10
10
|
def initialize(engine)
|
|
11
11
|
@engine = engine
|
|
12
12
|
@recv_queue = Routing.build_queue(engine.options.recv_hwm, :block)
|
|
13
|
-
@tasks = []
|
|
14
13
|
end
|
|
15
14
|
|
|
16
15
|
|
|
@@ -39,15 +38,14 @@ module OMQ
|
|
|
39
38
|
end
|
|
40
39
|
|
|
41
40
|
|
|
42
|
-
# @param connection [Connection]
|
|
41
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
43
42
|
#
|
|
44
43
|
def connection_added(connection)
|
|
45
|
-
|
|
46
|
-
@tasks << task if task
|
|
44
|
+
@engine.start_recv_pump(connection, @recv_queue)
|
|
47
45
|
end
|
|
48
46
|
|
|
49
47
|
|
|
50
|
-
# @param connection [Connection]
|
|
48
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
51
49
|
#
|
|
52
50
|
def connection_removed(connection)
|
|
53
51
|
# recv pump stops on EOFError via its connection barrier
|
|
@@ -60,16 +58,6 @@ module OMQ
|
|
|
60
58
|
raise "PULL sockets cannot send"
|
|
61
59
|
end
|
|
62
60
|
|
|
63
|
-
|
|
64
|
-
# Stops all background tasks.
|
|
65
|
-
#
|
|
66
|
-
# @return [void]
|
|
67
|
-
#
|
|
68
|
-
def stop
|
|
69
|
-
@tasks.each(&:stop)
|
|
70
|
-
@tasks.clear
|
|
71
|
-
end
|
|
72
|
-
|
|
73
61
|
end
|
|
74
62
|
end
|
|
75
63
|
end
|
data/lib/omq/routing/push.rb
CHANGED
|
@@ -12,7 +12,6 @@ module OMQ
|
|
|
12
12
|
#
|
|
13
13
|
def initialize(engine)
|
|
14
14
|
@engine = engine
|
|
15
|
-
@tasks = []
|
|
16
15
|
init_round_robin(engine)
|
|
17
16
|
end
|
|
18
17
|
|
|
@@ -34,7 +33,7 @@ module OMQ
|
|
|
34
33
|
end
|
|
35
34
|
|
|
36
35
|
|
|
37
|
-
# @param connection [Connection]
|
|
36
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
38
37
|
#
|
|
39
38
|
def connection_added(connection)
|
|
40
39
|
add_round_robin_send_connection(connection)
|
|
@@ -42,7 +41,7 @@ module OMQ
|
|
|
42
41
|
end
|
|
43
42
|
|
|
44
43
|
|
|
45
|
-
# @param connection [Connection]
|
|
44
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
46
45
|
#
|
|
47
46
|
def connection_removed(connection)
|
|
48
47
|
@connections.delete(connection)
|
|
@@ -57,14 +56,6 @@ module OMQ
|
|
|
57
56
|
end
|
|
58
57
|
|
|
59
58
|
|
|
60
|
-
# Stops all background tasks (send pumps, reapers).
|
|
61
|
-
#
|
|
62
|
-
def stop
|
|
63
|
-
@tasks.each(&:stop)
|
|
64
|
-
@tasks.clear
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
|
|
68
59
|
private
|
|
69
60
|
|
|
70
61
|
|
|
@@ -73,8 +64,8 @@ module OMQ
|
|
|
73
64
|
# may succeed if the kernel send buffer absorbs the data.
|
|
74
65
|
#
|
|
75
66
|
def start_reaper(conn)
|
|
76
|
-
return if conn.is_a?(Transport::Inproc::
|
|
77
|
-
@
|
|
67
|
+
return if conn.is_a?(Transport::Inproc::Pipe)
|
|
68
|
+
@engine.spawn_conn_pump_task(conn, annotation: "reaper") do
|
|
78
69
|
conn.receive_message # blocks until peer disconnects; then exits
|
|
79
70
|
end
|
|
80
71
|
end
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module OMQ
|
|
4
|
+
module Routing
|
|
5
|
+
# RADIO socket routing: group-based fan-out to DISH peers.
|
|
6
|
+
#
|
|
7
|
+
# Like PUB/FanOut but with exact group matching and JOIN/LEAVE
|
|
8
|
+
# commands instead of SUBSCRIBE/CANCEL.
|
|
9
|
+
#
|
|
10
|
+
# Messages are sent as two frames on the wire:
|
|
11
|
+
# group (MORE=1) + body (MORE=0)
|
|
12
|
+
#
|
|
13
|
+
class Radio
|
|
14
|
+
# Sentinel used for UDP connections that have no group filter:
|
|
15
|
+
# any group is considered a match.
|
|
16
|
+
#
|
|
17
|
+
ANY_GROUPS = Object.new.tap { |o| o.define_singleton_method(:include?) { |_| true } }.freeze
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# @return [Async::LimitedQueue]
|
|
21
|
+
#
|
|
22
|
+
attr_reader :send_queue
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# @param engine [Engine]
|
|
26
|
+
#
|
|
27
|
+
def initialize(engine)
|
|
28
|
+
@engine = engine
|
|
29
|
+
@connections = []
|
|
30
|
+
@groups = {} # connection => Set of joined groups (or ANY_GROUPS for UDP)
|
|
31
|
+
@send_queue = Routing.build_queue(engine.options.send_hwm, :block)
|
|
32
|
+
@on_mute = engine.options.on_mute
|
|
33
|
+
@send_pump_started = false
|
|
34
|
+
@conflate = engine.options.conflate
|
|
35
|
+
@written = Set.new
|
|
36
|
+
@latest = {} if @conflate
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
# RADIO is write-only.
|
|
41
|
+
#
|
|
42
|
+
def recv_queue
|
|
43
|
+
raise "RADIO sockets cannot receive"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
# No-op; RADIO has no recv queue to unblock.
|
|
48
|
+
#
|
|
49
|
+
def unblock_recv
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
54
|
+
#
|
|
55
|
+
def connection_added(connection)
|
|
56
|
+
@connections << connection
|
|
57
|
+
if connection.respond_to?(:read_frame)
|
|
58
|
+
@groups[connection] = Set.new
|
|
59
|
+
start_group_listener(connection)
|
|
60
|
+
else
|
|
61
|
+
@groups[connection] = ANY_GROUPS # UDP: fan-out to all groups
|
|
62
|
+
end
|
|
63
|
+
start_send_pump unless @send_pump_started
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
68
|
+
#
|
|
69
|
+
def connection_removed(connection)
|
|
70
|
+
@connections.delete(connection)
|
|
71
|
+
@groups.delete(connection)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
# Enqueues a message for sending.
|
|
76
|
+
#
|
|
77
|
+
# @param parts [Array<String>] [group, body]
|
|
78
|
+
#
|
|
79
|
+
def enqueue(parts)
|
|
80
|
+
@send_queue.enqueue(parts)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
# True when the send queue is empty.
|
|
85
|
+
#
|
|
86
|
+
def send_queues_drained?
|
|
87
|
+
@send_queue.empty?
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
private
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def muted?(conn)
|
|
95
|
+
return false if @on_mute == :block
|
|
96
|
+
q = conn.direct_recv_queue if conn.respond_to?(:direct_recv_queue)
|
|
97
|
+
q&.respond_to?(:limited?) && q.limited?
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def start_send_pump
|
|
102
|
+
@send_pump_started = true
|
|
103
|
+
@engine.spawn_pump_task(annotation: "send pump", parent: @engine.barrier) do
|
|
104
|
+
batch = []
|
|
105
|
+
|
|
106
|
+
loop do
|
|
107
|
+
@send_pump_idle = true
|
|
108
|
+
Routing.dequeue_batch(@send_queue, batch)
|
|
109
|
+
@send_pump_idle = false
|
|
110
|
+
|
|
111
|
+
@written.clear
|
|
112
|
+
|
|
113
|
+
if @conflate
|
|
114
|
+
# Keep only the last matching message per connection.
|
|
115
|
+
@latest.clear
|
|
116
|
+
batch.each do |parts|
|
|
117
|
+
group = parts[0]
|
|
118
|
+
body = parts[1] || EMPTY_BINARY
|
|
119
|
+
@connections.each do |conn|
|
|
120
|
+
next unless @groups[conn]&.include?(group)
|
|
121
|
+
@latest[conn] = [group, body]
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
@latest.each do |conn, msg|
|
|
125
|
+
next if muted?(conn)
|
|
126
|
+
begin
|
|
127
|
+
conn.write_message(msg)
|
|
128
|
+
@written << conn
|
|
129
|
+
rescue *CONNECTION_LOST
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
else
|
|
133
|
+
batch.each do |parts|
|
|
134
|
+
group = parts[0]
|
|
135
|
+
body = parts[1] || EMPTY_BINARY
|
|
136
|
+
msg = [group, body]
|
|
137
|
+
wire_bytes = nil
|
|
138
|
+
|
|
139
|
+
@connections.each do |conn|
|
|
140
|
+
next unless @groups[conn]&.include?(group)
|
|
141
|
+
next if muted?(conn)
|
|
142
|
+
begin
|
|
143
|
+
if conn.respond_to?(:curve?) && conn.curve?
|
|
144
|
+
conn.write_message(msg)
|
|
145
|
+
elsif conn.respond_to?(:write_wire)
|
|
146
|
+
wire_bytes ||= Protocol::ZMTP::Codec::Frame.encode_message(msg)
|
|
147
|
+
conn.write_wire(wire_bytes)
|
|
148
|
+
else
|
|
149
|
+
conn.write_message(msg)
|
|
150
|
+
end
|
|
151
|
+
@written << conn
|
|
152
|
+
rescue *CONNECTION_LOST
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
@written.each do |conn|
|
|
159
|
+
conn.flush
|
|
160
|
+
rescue *CONNECTION_LOST
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
batch.clear
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def start_group_listener(conn)
|
|
170
|
+
@engine.spawn_conn_pump_task(conn, annotation: "group listener") do
|
|
171
|
+
loop do
|
|
172
|
+
frame = conn.read_frame
|
|
173
|
+
next unless frame.command?
|
|
174
|
+
cmd = Protocol::ZMTP::Codec::Command.from_body(frame.body)
|
|
175
|
+
case cmd.name
|
|
176
|
+
when "JOIN"
|
|
177
|
+
@groups[conn]&.add(cmd.data)
|
|
178
|
+
when "LEAVE"
|
|
179
|
+
@groups[conn]&.delete(cmd.data)
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
end
|
data/lib/omq/routing/rep.rb
CHANGED
|
@@ -23,9 +23,7 @@ module OMQ
|
|
|
23
23
|
@engine = engine
|
|
24
24
|
@recv_queue = Routing.build_queue(engine.options.recv_hwm, :block)
|
|
25
25
|
@pending_replies = []
|
|
26
|
-
@conn_queues = {}
|
|
27
|
-
@conn_send_tasks = {} # connection => send pump task
|
|
28
|
-
@tasks = []
|
|
26
|
+
@conn_queues = {}
|
|
29
27
|
end
|
|
30
28
|
|
|
31
29
|
|
|
@@ -47,10 +45,10 @@ module OMQ
|
|
|
47
45
|
end
|
|
48
46
|
|
|
49
47
|
|
|
50
|
-
# @param connection [Connection]
|
|
48
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
51
49
|
#
|
|
52
50
|
def connection_added(connection)
|
|
53
|
-
|
|
51
|
+
@engine.start_recv_pump(connection, @recv_queue) do |msg|
|
|
54
52
|
delimiter = msg.index { |p| p.empty? } || msg.size
|
|
55
53
|
envelope = msg[0, delimiter]
|
|
56
54
|
body = msg[(delimiter + 1)..] || []
|
|
@@ -58,20 +56,18 @@ module OMQ
|
|
|
58
56
|
@pending_replies << [connection, envelope]
|
|
59
57
|
body
|
|
60
58
|
end
|
|
61
|
-
@tasks << task if task
|
|
62
59
|
|
|
63
60
|
q = Routing.build_queue(@engine.options.send_hwm, :block)
|
|
64
61
|
@conn_queues[connection] = q
|
|
65
|
-
|
|
62
|
+
ConnSendPump.start(@engine, connection, q)
|
|
66
63
|
end
|
|
67
64
|
|
|
68
65
|
|
|
69
|
-
# @param connection [Connection]
|
|
66
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
70
67
|
#
|
|
71
68
|
def connection_removed(connection)
|
|
72
69
|
@pending_replies.reject! { |r| r[0] == connection }
|
|
73
70
|
@conn_queues.delete(connection)
|
|
74
|
-
@conn_send_tasks.delete(connection)&.stop
|
|
75
71
|
end
|
|
76
72
|
|
|
77
73
|
|
|
@@ -92,16 +88,6 @@ module OMQ
|
|
|
92
88
|
end
|
|
93
89
|
|
|
94
90
|
|
|
95
|
-
# Stops all background tasks.
|
|
96
|
-
#
|
|
97
|
-
# @return [void]
|
|
98
|
-
#
|
|
99
|
-
def stop
|
|
100
|
-
@tasks.each(&:stop)
|
|
101
|
-
@tasks.clear
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
|
|
105
91
|
# @return [Boolean] true when all per-connection send queues are empty
|
|
106
92
|
#
|
|
107
93
|
def send_queues_drained?
|
data/lib/omq/routing/req.rb
CHANGED
|
@@ -21,10 +21,9 @@ module OMQ
|
|
|
21
21
|
# @param engine [Engine]
|
|
22
22
|
#
|
|
23
23
|
def initialize(engine)
|
|
24
|
-
@engine
|
|
25
|
-
@recv_queue
|
|
26
|
-
@
|
|
27
|
-
@state = :ready # :ready or :waiting_reply
|
|
24
|
+
@engine = engine
|
|
25
|
+
@recv_queue = Routing.build_queue(engine.options.recv_hwm, :block)
|
|
26
|
+
@state = :ready # :ready or :waiting_reply
|
|
28
27
|
init_round_robin(engine)
|
|
29
28
|
end
|
|
30
29
|
|
|
@@ -47,20 +46,19 @@ module OMQ
|
|
|
47
46
|
end
|
|
48
47
|
|
|
49
48
|
|
|
50
|
-
# @param connection [Connection]
|
|
49
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
51
50
|
#
|
|
52
51
|
def connection_added(connection)
|
|
53
|
-
|
|
52
|
+
@engine.start_recv_pump(connection, @recv_queue) do |msg|
|
|
54
53
|
@state = :ready
|
|
55
54
|
msg.first&.empty? ? msg[1..] : msg
|
|
56
55
|
end
|
|
57
56
|
|
|
58
|
-
@tasks << task if task
|
|
59
57
|
add_round_robin_send_connection(connection)
|
|
60
58
|
end
|
|
61
59
|
|
|
62
60
|
|
|
63
|
-
# @param connection [Connection]
|
|
61
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
64
62
|
#
|
|
65
63
|
def connection_removed(connection)
|
|
66
64
|
@connections.delete(connection)
|
|
@@ -77,16 +75,6 @@ module OMQ
|
|
|
77
75
|
end
|
|
78
76
|
|
|
79
77
|
|
|
80
|
-
# Stops all background tasks.
|
|
81
|
-
#
|
|
82
|
-
# @return [void]
|
|
83
|
-
#
|
|
84
|
-
def stop
|
|
85
|
-
@tasks.each(&:stop)
|
|
86
|
-
@tasks.clear
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
|
|
90
78
|
private
|
|
91
79
|
|
|
92
80
|
|