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
|
@@ -12,7 +12,7 @@ module OMQ
|
|
|
12
12
|
# which is strictly better than libzmq's strict per-pipe round-robin
|
|
13
13
|
# for PUSH-style patterns.
|
|
14
14
|
#
|
|
15
|
-
# See DESIGN.md "Per-socket HWM (not per-connection)" for the
|
|
15
|
+
# See doc/DESIGN.md "Per-socket HWM (not per-connection)" for the
|
|
16
16
|
# full reasoning.
|
|
17
17
|
#
|
|
18
18
|
# Including classes must call `init_round_robin(engine)` from
|
|
@@ -38,18 +38,17 @@ module OMQ
|
|
|
38
38
|
# @param engine [Engine]
|
|
39
39
|
#
|
|
40
40
|
def init_round_robin(engine)
|
|
41
|
-
@connections
|
|
42
|
-
@send_queue
|
|
43
|
-
@direct_pipe
|
|
44
|
-
@
|
|
45
|
-
@in_flight = 0 # messages dequeued but not yet written
|
|
41
|
+
@connections = []
|
|
42
|
+
@send_queue = Routing.build_queue(engine.options.send_hwm, :block)
|
|
43
|
+
@direct_pipe = nil
|
|
44
|
+
@in_flight = 0 # messages dequeued but not yet written
|
|
46
45
|
end
|
|
47
46
|
|
|
48
47
|
|
|
49
48
|
# Registers a connection and starts its send pump.
|
|
50
49
|
# Call from #connection_added.
|
|
51
50
|
#
|
|
52
|
-
# @param conn [Connection]
|
|
51
|
+
# @param conn [Protocol::ZMTP::Connection]
|
|
53
52
|
#
|
|
54
53
|
def add_round_robin_send_connection(conn)
|
|
55
54
|
@connections << conn
|
|
@@ -58,23 +57,23 @@ module OMQ
|
|
|
58
57
|
end
|
|
59
58
|
|
|
60
59
|
|
|
61
|
-
# Removes the connection
|
|
62
|
-
#
|
|
63
|
-
#
|
|
64
|
-
#
|
|
60
|
+
# Removes the connection. Any message the pump had already
|
|
61
|
+
# dequeued but not yet written is dropped — matching libzmq's
|
|
62
|
+
# behavior on `pipe_terminated`. PUSH has no cross-peer ordering
|
|
63
|
+
# guarantee, so this is safe. The pump itself is torn down by
|
|
64
|
+
# the per-connection lifecycle barrier.
|
|
65
65
|
#
|
|
66
|
-
# @param conn [Connection]
|
|
66
|
+
# @param conn [Protocol::ZMTP::Connection]
|
|
67
67
|
#
|
|
68
68
|
def remove_round_robin_send_connection(conn)
|
|
69
69
|
update_direct_pipe
|
|
70
|
-
@conn_send_tasks.delete(conn)
|
|
71
70
|
end
|
|
72
71
|
|
|
73
72
|
|
|
74
73
|
# Updates the direct-pipe shortcut for inproc single-peer bypass.
|
|
75
74
|
#
|
|
76
75
|
def update_direct_pipe
|
|
77
|
-
if @connections.size == 1 && @connections.first.is_a?(Transport::Inproc::
|
|
76
|
+
if @connections.size == 1 && @connections.first.is_a?(Transport::Inproc::Pipe)
|
|
78
77
|
@direct_pipe = @connections.first
|
|
79
78
|
else
|
|
80
79
|
@direct_pipe = nil
|
|
@@ -129,10 +128,10 @@ module OMQ
|
|
|
129
128
|
# run. The yield is effectively free when the scheduler has no
|
|
130
129
|
# other work.
|
|
131
130
|
#
|
|
132
|
-
# @param conn [Connection]
|
|
131
|
+
# @param conn [Protocol::ZMTP::Connection]
|
|
133
132
|
#
|
|
134
133
|
def start_conn_send_pump(conn)
|
|
135
|
-
|
|
134
|
+
@engine.spawn_conn_pump_task(conn, annotation: "send pump") do
|
|
136
135
|
batch = []
|
|
137
136
|
|
|
138
137
|
loop do
|
|
@@ -153,9 +152,6 @@ module OMQ
|
|
|
153
152
|
Async::Task.current.yield
|
|
154
153
|
end
|
|
155
154
|
end
|
|
156
|
-
|
|
157
|
-
@conn_send_tasks[conn] = task
|
|
158
|
-
@tasks << task
|
|
159
155
|
end
|
|
160
156
|
|
|
161
157
|
|
data/lib/omq/routing/router.rb
CHANGED
|
@@ -23,9 +23,7 @@ module OMQ
|
|
|
23
23
|
@recv_queue = Routing.build_queue(engine.options.recv_hwm, :block)
|
|
24
24
|
@connections_by_identity = {}
|
|
25
25
|
@identity_by_connection = {}
|
|
26
|
-
@conn_queues = {}
|
|
27
|
-
@conn_send_tasks = {} # connection => send pump task
|
|
28
|
-
@tasks = []
|
|
26
|
+
@conn_queues = {}
|
|
29
27
|
end
|
|
30
28
|
|
|
31
29
|
|
|
@@ -47,7 +45,7 @@ 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
|
identity = connection.peer_identity
|
|
@@ -55,22 +53,20 @@ module OMQ
|
|
|
55
53
|
@connections_by_identity[identity] = connection
|
|
56
54
|
@identity_by_connection[connection] = identity
|
|
57
55
|
|
|
58
|
-
|
|
59
|
-
@tasks << task if task
|
|
56
|
+
@engine.start_recv_pump(connection, @recv_queue) { |msg| [identity, *msg] }
|
|
60
57
|
|
|
61
58
|
q = Routing.build_queue(@engine.options.send_hwm, :block)
|
|
62
59
|
@conn_queues[connection] = q
|
|
63
|
-
|
|
60
|
+
ConnSendPump.start(@engine, connection, q)
|
|
64
61
|
end
|
|
65
62
|
|
|
66
63
|
|
|
67
|
-
# @param connection [Connection]
|
|
64
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
68
65
|
#
|
|
69
66
|
def connection_removed(connection)
|
|
70
67
|
identity = @identity_by_connection.delete(connection)
|
|
71
68
|
@connections_by_identity.delete(identity) if identity
|
|
72
69
|
@conn_queues.delete(connection)
|
|
73
|
-
@conn_send_tasks.delete(connection)&.stop
|
|
74
70
|
end
|
|
75
71
|
|
|
76
72
|
|
|
@@ -91,16 +87,6 @@ module OMQ
|
|
|
91
87
|
end
|
|
92
88
|
|
|
93
89
|
|
|
94
|
-
# Stops all background tasks.
|
|
95
|
-
#
|
|
96
|
-
# @return [void]
|
|
97
|
-
#
|
|
98
|
-
def stop
|
|
99
|
-
@tasks.each(&:stop)
|
|
100
|
-
@tasks.clear
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
|
|
104
90
|
# @return [Boolean] true when all per-connection send queues are empty
|
|
105
91
|
#
|
|
106
92
|
def send_queues_drained?
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module OMQ
|
|
4
|
+
module Routing
|
|
5
|
+
# SCATTER socket routing: round-robin send to GATHER peers.
|
|
6
|
+
#
|
|
7
|
+
class Scatter
|
|
8
|
+
include RoundRobin
|
|
9
|
+
|
|
10
|
+
# @param engine [Engine]
|
|
11
|
+
#
|
|
12
|
+
def initialize(engine)
|
|
13
|
+
@engine = engine
|
|
14
|
+
init_round_robin(engine)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
# SCATTER is write-only.
|
|
19
|
+
#
|
|
20
|
+
def recv_queue
|
|
21
|
+
raise "SCATTER sockets cannot receive"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def dequeue_recv
|
|
26
|
+
raise "SCATTER sockets cannot receive"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
# No-op; SCATTER has no recv queue to unblock.
|
|
31
|
+
#
|
|
32
|
+
def unblock_recv
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
37
|
+
#
|
|
38
|
+
def connection_added(connection)
|
|
39
|
+
add_round_robin_send_connection(connection)
|
|
40
|
+
start_reaper(connection)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
45
|
+
#
|
|
46
|
+
def connection_removed(connection)
|
|
47
|
+
@connections.delete(connection)
|
|
48
|
+
remove_round_robin_send_connection(connection)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
# @param parts [Array<String>]
|
|
53
|
+
#
|
|
54
|
+
def enqueue(parts)
|
|
55
|
+
enqueue_round_robin(parts)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
# Detects peer disconnection on write-only sockets by
|
|
63
|
+
# blocking on a receive that only returns on disconnect.
|
|
64
|
+
#
|
|
65
|
+
# @param conn [Protocol::ZMTP::Connection]
|
|
66
|
+
#
|
|
67
|
+
def start_reaper(conn)
|
|
68
|
+
return if conn.is_a?(Transport::Inproc::Pipe)
|
|
69
|
+
@engine.spawn_conn_pump_task(conn, annotation: "reaper") do
|
|
70
|
+
conn.receive_message # blocks until peer disconnects; then exits
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "securerandom"
|
|
4
|
+
|
|
5
|
+
module OMQ
|
|
6
|
+
module Routing
|
|
7
|
+
# SERVER socket routing: identity-based routing 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 Server
|
|
14
|
+
# @return [Async::LimitedQueue]
|
|
15
|
+
#
|
|
16
|
+
attr_reader :recv_queue
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# @param engine [Engine]
|
|
20
|
+
#
|
|
21
|
+
def initialize(engine)
|
|
22
|
+
@engine = engine
|
|
23
|
+
@recv_queue = Routing.build_queue(engine.options.recv_hwm, :block)
|
|
24
|
+
@connections_by_routing_id = {}
|
|
25
|
+
@routing_id_by_connection = {}
|
|
26
|
+
@conn_queues = {}
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
# Dequeues the next received message. Blocks until one is available.
|
|
31
|
+
#
|
|
32
|
+
# @return [Array<String>, nil]
|
|
33
|
+
#
|
|
34
|
+
def dequeue_recv
|
|
35
|
+
@recv_queue.dequeue
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
# Wakes a blocked {#dequeue_recv} with a nil sentinel.
|
|
40
|
+
#
|
|
41
|
+
# @return [void]
|
|
42
|
+
#
|
|
43
|
+
def unblock_recv
|
|
44
|
+
@recv_queue.enqueue(nil)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
49
|
+
#
|
|
50
|
+
def connection_added(connection)
|
|
51
|
+
routing_id = SecureRandom.bytes(4)
|
|
52
|
+
@connections_by_routing_id[routing_id] = connection
|
|
53
|
+
@routing_id_by_connection[connection] = routing_id
|
|
54
|
+
|
|
55
|
+
@engine.start_recv_pump(connection, @recv_queue) { |msg| [routing_id, *msg] }
|
|
56
|
+
|
|
57
|
+
q = Routing.build_queue(@engine.options.send_hwm, :block)
|
|
58
|
+
@conn_queues[connection] = q
|
|
59
|
+
ConnSendPump.start(@engine, connection, q)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
64
|
+
#
|
|
65
|
+
def connection_removed(connection)
|
|
66
|
+
routing_id = @routing_id_by_connection.delete(connection)
|
|
67
|
+
@connections_by_routing_id.delete(routing_id) if routing_id
|
|
68
|
+
@conn_queues.delete(connection)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
# @param parts [Array<String>]
|
|
73
|
+
#
|
|
74
|
+
def enqueue(parts)
|
|
75
|
+
routing_id = parts.first
|
|
76
|
+
conn = @connections_by_routing_id[routing_id]
|
|
77
|
+
return unless conn
|
|
78
|
+
@conn_queues[conn]&.enqueue(parts[1..])
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
# True when all per-connection send queues are empty.
|
|
83
|
+
#
|
|
84
|
+
def send_queues_drained?
|
|
85
|
+
@conn_queues.values.all?(&:empty?)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
data/lib/omq/routing/sub.rb
CHANGED
|
@@ -20,7 +20,6 @@ module OMQ
|
|
|
20
20
|
@connections = Set.new
|
|
21
21
|
@recv_queue = Routing.build_queue(engine.options.recv_hwm, :block)
|
|
22
22
|
@subscriptions = Set.new
|
|
23
|
-
@tasks = []
|
|
24
23
|
end
|
|
25
24
|
|
|
26
25
|
|
|
@@ -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_added(connection)
|
|
48
47
|
@connections << connection
|
|
@@ -51,12 +50,11 @@ module OMQ
|
|
|
51
50
|
send_subscribe(connection, prefix)
|
|
52
51
|
end
|
|
53
52
|
|
|
54
|
-
|
|
55
|
-
@tasks << task if task
|
|
53
|
+
@engine.start_recv_pump(connection, @recv_queue)
|
|
56
54
|
end
|
|
57
55
|
|
|
58
56
|
|
|
59
|
-
# @param connection [Connection]
|
|
57
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
60
58
|
#
|
|
61
59
|
def connection_removed(connection)
|
|
62
60
|
@connections.delete(connection)
|
|
@@ -90,16 +88,6 @@ module OMQ
|
|
|
90
88
|
end
|
|
91
89
|
|
|
92
90
|
|
|
93
|
-
# Stops all background tasks.
|
|
94
|
-
#
|
|
95
|
-
# @return [void]
|
|
96
|
-
#
|
|
97
|
-
def stop
|
|
98
|
-
@tasks.each(&:stop)
|
|
99
|
-
@tasks.clear
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
|
|
103
91
|
private
|
|
104
92
|
|
|
105
93
|
|
data/lib/omq/routing/xpub.rb
CHANGED
|
@@ -24,7 +24,6 @@ module OMQ
|
|
|
24
24
|
def initialize(engine)
|
|
25
25
|
@engine = engine
|
|
26
26
|
@recv_queue = Routing.build_queue(engine.options.recv_hwm, :block)
|
|
27
|
-
@tasks = []
|
|
28
27
|
|
|
29
28
|
init_fan_out(engine)
|
|
30
29
|
end
|
|
@@ -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_added(connection)
|
|
48
47
|
@connections << connection
|
|
@@ -52,7 +51,7 @@ module OMQ
|
|
|
52
51
|
end
|
|
53
52
|
|
|
54
53
|
|
|
55
|
-
# @param connection [Connection]
|
|
54
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
56
55
|
#
|
|
57
56
|
def connection_removed(connection)
|
|
58
57
|
@connections.delete(connection)
|
|
@@ -68,16 +67,6 @@ module OMQ
|
|
|
68
67
|
end
|
|
69
68
|
|
|
70
69
|
|
|
71
|
-
# Stops all background tasks.
|
|
72
|
-
#
|
|
73
|
-
# @return [void]
|
|
74
|
-
#
|
|
75
|
-
def stop
|
|
76
|
-
@tasks.each(&:stop)
|
|
77
|
-
@tasks.clear
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
|
|
81
70
|
private
|
|
82
71
|
|
|
83
72
|
|
data/lib/omq/routing/xsub.rb
CHANGED
|
@@ -18,12 +18,10 @@ module OMQ
|
|
|
18
18
|
# @param engine [Engine]
|
|
19
19
|
#
|
|
20
20
|
def initialize(engine)
|
|
21
|
-
@engine
|
|
22
|
-
@connections
|
|
23
|
-
@recv_queue
|
|
24
|
-
@conn_queues
|
|
25
|
-
@conn_send_tasks = {} # connection => send pump task
|
|
26
|
-
@tasks = []
|
|
21
|
+
@engine = engine
|
|
22
|
+
@connections = Set.new
|
|
23
|
+
@recv_queue = Routing.build_queue(engine.options.recv_hwm, :block)
|
|
24
|
+
@conn_queues = {}
|
|
27
25
|
end
|
|
28
26
|
|
|
29
27
|
|
|
@@ -45,13 +43,12 @@ module OMQ
|
|
|
45
43
|
end
|
|
46
44
|
|
|
47
45
|
|
|
48
|
-
# @param connection [Connection]
|
|
46
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
49
47
|
#
|
|
50
48
|
def connection_added(connection)
|
|
51
49
|
@connections << connection
|
|
52
50
|
|
|
53
|
-
|
|
54
|
-
@tasks << task if task
|
|
51
|
+
@engine.start_recv_pump(connection, @recv_queue)
|
|
55
52
|
|
|
56
53
|
q = Routing.build_queue(@engine.options.send_hwm, :block)
|
|
57
54
|
@conn_queues[connection] = q
|
|
@@ -59,12 +56,11 @@ module OMQ
|
|
|
59
56
|
end
|
|
60
57
|
|
|
61
58
|
|
|
62
|
-
# @param connection [Connection]
|
|
59
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
63
60
|
#
|
|
64
61
|
def connection_removed(connection)
|
|
65
62
|
@connections.delete(connection)
|
|
66
63
|
@conn_queues.delete(connection)
|
|
67
|
-
@conn_send_tasks.delete(connection)&.stop
|
|
68
64
|
end
|
|
69
65
|
|
|
70
66
|
|
|
@@ -79,16 +75,6 @@ module OMQ
|
|
|
79
75
|
end
|
|
80
76
|
|
|
81
77
|
|
|
82
|
-
# Stops all background tasks.
|
|
83
|
-
#
|
|
84
|
-
# @return [void]
|
|
85
|
-
#
|
|
86
|
-
def stop
|
|
87
|
-
@tasks.each(&:stop)
|
|
88
|
-
@tasks.clear
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
|
|
92
78
|
# @return [Boolean] true when all per-connection send queues are empty
|
|
93
79
|
#
|
|
94
80
|
def send_queues_drained?
|
|
@@ -100,7 +86,7 @@ module OMQ
|
|
|
100
86
|
|
|
101
87
|
|
|
102
88
|
def start_conn_send_pump(conn, q)
|
|
103
|
-
|
|
89
|
+
@engine.spawn_conn_pump_task(conn, annotation: "send pump") do
|
|
104
90
|
loop do
|
|
105
91
|
parts = q.dequeue
|
|
106
92
|
frame = parts.first&.b
|
|
@@ -128,9 +114,6 @@ module OMQ
|
|
|
128
114
|
end
|
|
129
115
|
end
|
|
130
116
|
end
|
|
131
|
-
|
|
132
|
-
@conn_send_tasks[conn] = task
|
|
133
|
-
@tasks << task
|
|
134
117
|
end
|
|
135
118
|
|
|
136
119
|
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# OMQ SCATTER/GATHER socket types (ZeroMQ RFC 49).
|
|
4
|
+
#
|
|
5
|
+
# Not loaded by +require "omq"+; opt in with:
|
|
6
|
+
#
|
|
7
|
+
# require "omq/scatter_gather"
|
|
8
|
+
|
|
9
|
+
require "omq"
|
|
10
|
+
require_relative "routing/scatter"
|
|
11
|
+
require_relative "routing/gather"
|
|
12
|
+
|
|
13
|
+
module OMQ
|
|
14
|
+
# Pipeline sender socket that round-robins to GATHER peers (ZeroMQ RFC 49).
|
|
15
|
+
class SCATTER < Socket
|
|
16
|
+
include Writable
|
|
17
|
+
include SingleFrame
|
|
18
|
+
|
|
19
|
+
# Creates a new SCATTER socket.
|
|
20
|
+
#
|
|
21
|
+
# @param endpoints [String, Array<String>, nil] endpoint(s) to connect to
|
|
22
|
+
# @param linger [Numeric] linger period in seconds (Float::INFINITY = wait forever, 0 = drop)
|
|
23
|
+
# @param send_hwm [Integer, nil] send high-water mark
|
|
24
|
+
# @param send_timeout [Integer, nil] send timeout in seconds
|
|
25
|
+
# @param backend [Object, nil] optional transport backend
|
|
26
|
+
def initialize(endpoints = nil, linger: Float::INFINITY, send_hwm: nil, send_timeout: nil, backend: nil)
|
|
27
|
+
init_engine(:SCATTER, send_hwm: send_hwm, send_timeout: send_timeout, backend: backend)
|
|
28
|
+
@options.linger = linger
|
|
29
|
+
attach_endpoints(endpoints, default: :connect)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# Pipeline receiver socket that fair-queues from SCATTER peers (ZeroMQ RFC 49).
|
|
35
|
+
class GATHER < Socket
|
|
36
|
+
include Readable
|
|
37
|
+
include SingleFrame
|
|
38
|
+
|
|
39
|
+
# Creates a new GATHER socket.
|
|
40
|
+
#
|
|
41
|
+
# @param endpoints [String, Array<String>, nil] endpoint(s) to bind to
|
|
42
|
+
# @param linger [Numeric] linger period in seconds (Float::INFINITY = wait forever, 0 = drop)
|
|
43
|
+
# @param recv_hwm [Integer, nil] receive high-water mark
|
|
44
|
+
# @param recv_timeout [Integer, nil] receive timeout in seconds
|
|
45
|
+
# @param backend [Object, nil] optional transport backend
|
|
46
|
+
def initialize(endpoints = nil, linger: Float::INFINITY, recv_hwm: nil, recv_timeout: nil, backend: nil)
|
|
47
|
+
init_engine(:GATHER, recv_hwm: recv_hwm, recv_timeout: recv_timeout, backend: backend)
|
|
48
|
+
@options.linger = linger
|
|
49
|
+
attach_endpoints(endpoints, default: :bind)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
Routing.register(:SCATTER, Routing::Scatter)
|
|
55
|
+
Routing.register(:GATHER, Routing::Gather)
|
|
56
|
+
end
|
data/lib/omq/socket.rb
CHANGED
|
@@ -35,11 +35,6 @@ module OMQ
|
|
|
35
35
|
attr_reader :options
|
|
36
36
|
|
|
37
37
|
|
|
38
|
-
# @return [Integer, nil] last auto-selected TCP port
|
|
39
|
-
#
|
|
40
|
-
attr_reader :last_tcp_port
|
|
41
|
-
|
|
42
|
-
|
|
43
38
|
# @return [Engine] the socket's engine. Exposed for peer tooling
|
|
44
39
|
# (omq-cli, omq-ffi, omq-ractor) that needs to reach into the
|
|
45
40
|
# socket's internals — not part of the stable user API.
|
|
@@ -109,14 +104,11 @@ module OMQ
|
|
|
109
104
|
# can coordinate teardown with their own Async tree. Only the
|
|
110
105
|
# *first* bind/connect call captures the parent — subsequent
|
|
111
106
|
# calls ignore the kwarg.
|
|
112
|
-
# @return [
|
|
107
|
+
# @return [URI::Generic] resolved endpoint URI (with auto-selected port for "tcp://host:0")
|
|
113
108
|
#
|
|
114
|
-
def bind(endpoint, parent: nil)
|
|
109
|
+
def bind(endpoint, parent: nil, **opts)
|
|
115
110
|
ensure_parent_task(parent: parent)
|
|
116
|
-
Reactor.run
|
|
117
|
-
@engine.bind(endpoint) # TODO: use timeout?
|
|
118
|
-
@last_tcp_port = @engine.last_tcp_port
|
|
119
|
-
end
|
|
111
|
+
Reactor.run { @engine.bind(endpoint, **opts) } # TODO: use timeout?
|
|
120
112
|
end
|
|
121
113
|
|
|
122
114
|
|
|
@@ -124,11 +116,11 @@ module OMQ
|
|
|
124
116
|
#
|
|
125
117
|
# @param endpoint [String]
|
|
126
118
|
# @param parent [#async, nil] see {#bind}.
|
|
127
|
-
# @return [
|
|
119
|
+
# @return [URI::Generic] parsed endpoint URI
|
|
128
120
|
#
|
|
129
|
-
def connect(endpoint, parent: nil)
|
|
121
|
+
def connect(endpoint, parent: nil, **opts)
|
|
130
122
|
ensure_parent_task(parent: parent)
|
|
131
|
-
Reactor.run { @engine.connect(endpoint) } # TODO: use timeout?
|
|
123
|
+
Reactor.run { @engine.connect(endpoint, **opts) } # TODO: use timeout?
|
|
132
124
|
end
|
|
133
125
|
|
|
134
126
|
|
|
@@ -152,13 +144,6 @@ module OMQ
|
|
|
152
144
|
end
|
|
153
145
|
|
|
154
146
|
|
|
155
|
-
# @return [String, nil] last bound endpoint
|
|
156
|
-
#
|
|
157
|
-
def last_endpoint
|
|
158
|
-
@engine.last_endpoint
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
|
|
162
147
|
# @return [Async::Promise] resolves when first peer completes handshake
|
|
163
148
|
def peer_connected
|
|
164
149
|
@engine.peer_connected
|
|
@@ -167,7 +152,7 @@ module OMQ
|
|
|
167
152
|
|
|
168
153
|
# @return [Async::Promise] resolves when first subscriber joins (PUB/XPUB only)
|
|
169
154
|
def subscriber_joined
|
|
170
|
-
@engine.
|
|
155
|
+
@engine.subscriber_joined
|
|
171
156
|
end
|
|
172
157
|
|
|
173
158
|
|
|
@@ -285,7 +270,7 @@ module OMQ
|
|
|
285
270
|
# @return [String]
|
|
286
271
|
#
|
|
287
272
|
def inspect
|
|
288
|
-
format("#<%s
|
|
273
|
+
format("#<%s bound=%p>", self.class, @engine.listeners.keys)
|
|
289
274
|
end
|
|
290
275
|
|
|
291
276
|
|