omq 0.23.0 → 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 +47 -0
- data/lib/omq/client_server.rb +1 -1
- data/lib/omq/engine/connection_lifecycle.rb +12 -6
- data/lib/omq/engine/heartbeat.rb +1 -1
- data/lib/omq/engine/recv_pump.rb +7 -6
- data/lib/omq/engine.rb +6 -5
- data/lib/omq/peer.rb +1 -1
- data/lib/omq/radio_dish.rb +1 -1
- data/lib/omq/readable.rb +5 -1
- data/lib/omq/routing/channel.rb +4 -4
- data/lib/omq/routing/client.rb +2 -2
- data/lib/omq/routing/conn_send_pump.rb +1 -1
- data/lib/omq/routing/dealer.rb +2 -2
- data/lib/omq/routing/dish.rb +2 -2
- data/lib/omq/routing/fan_out.rb +7 -7
- data/lib/omq/routing/gather.rb +2 -2
- data/lib/omq/routing/pair.rb +4 -4
- data/lib/omq/routing/peer.rb +2 -2
- data/lib/omq/routing/pub.rb +2 -2
- data/lib/omq/routing/pull.rb +2 -2
- data/lib/omq/routing/push.rb +3 -3
- data/lib/omq/routing/radio.rb +2 -2
- data/lib/omq/routing/rep.rb +2 -2
- data/lib/omq/routing/req.rb +2 -2
- data/lib/omq/routing/round_robin.rb +4 -4
- data/lib/omq/routing/router.rb +2 -2
- data/lib/omq/routing/scatter.rb +4 -5
- data/lib/omq/routing/server.rb +2 -2
- data/lib/omq/routing/sub.rb +2 -2
- data/lib/omq/routing/xpub.rb +2 -2
- data/lib/omq/routing/xsub.rb +2 -2
- data/lib/omq/transport/inproc/{direct_pipe.rb → pipe.rb} +9 -9
- data/lib/omq/transport/inproc.rb +11 -11
- data/lib/omq/transport/udp.rb +1 -1
- data/lib/omq/version.rb +1 -1
- data/lib/omq/writable.rb +11 -42
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ed87cc3a3243100b7977fd58f102b87918de8568cf8739642afc6377bb3f76e5
|
|
4
|
+
data.tar.gz: f01b30844ae48ffe26ec3934fef780521937a7611e1d00c87b333136fa5641ac
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 853d3171298de868ad3de28fe284c7970ddf196203bbb217fc91fa62cebb9d39c1d278b53d4259d0dc505b09457624ea68f4a9a8a0e654850c9266139a1fa05e
|
|
7
|
+
data.tar.gz: ad8a2cec518ceebac32055aeab7fd159d982421e9983670ec28182094f4fe2338f89cd7a1609d02cd8720f01c121159fec7e2489b8c816f9f16adf9d950c34c4
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,52 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.24.0 — 2026-04-18
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- **Caller owns message parts.** `Writable#send` no longer deep-freezes or
|
|
8
|
+
binary-coerces the caller's input. The contract is now libzmq-style:
|
|
9
|
+
don't mutate parts after sending. `#receive` likewise returns mutable
|
|
10
|
+
arrays of mutable strings. This removes a full-payload allocation per
|
|
11
|
+
message (`.b.freeze`) on the send path and a per-frame freeze on the
|
|
12
|
+
receive path.
|
|
13
|
+
|
|
14
|
+
- **No more implicit `#to_s` / nil coercion.** Passing a non-string part
|
|
15
|
+
(e.g. Integer, Symbol, nil) will raise `NoMethodError` at the wire layer
|
|
16
|
+
instead of being silently converted. The `EMPTY_PART` constant is gone.
|
|
17
|
+
|
|
18
|
+
- **Reactor fast path for `#send` / `#receive`.** When the socket was
|
|
19
|
+
bound/connected from an Async fiber, hot-path I/O skips `Reactor.run`
|
|
20
|
+
entirely and calls the engine directly (with an `Async::Task#with_timeout`
|
|
21
|
+
wrapper only when a timeout is configured). The shared IO thread is used
|
|
22
|
+
only when the socket was created from a non-Async thread.
|
|
23
|
+
|
|
24
|
+
### Performance
|
|
25
|
+
|
|
26
|
+
Combined effect of caller-owns-data + Reactor fast path on inproc:
|
|
27
|
+
|
|
28
|
+
- PUSH/PULL inproc 1-peer: **+105% to +128%** msg/s across payload sizes
|
|
29
|
+
- PUSH/PULL inproc 3-peer: **+63% to +111%** msg/s
|
|
30
|
+
- PUSH/PULL ipc: +5% to +17%
|
|
31
|
+
- TCP numbers unchanged (OS/syscall-dominated)
|
|
32
|
+
|
|
33
|
+
### Removed
|
|
34
|
+
|
|
35
|
+
- `Writable#freeze_message` and `#frozen_binary` private helpers.
|
|
36
|
+
- `Writable::EMPTY_PART` constant.
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
## 0.23.1 — 2026-04-18
|
|
40
|
+
|
|
41
|
+
### Fixed
|
|
42
|
+
|
|
43
|
+
- **SCATTER double-tracked each peer.** `Routing::Scatter#connection_added`
|
|
44
|
+
appended to `@connections` and then called `add_round_robin_send_connection`,
|
|
45
|
+
which appends again — so every connected peer had two entries in the list.
|
|
46
|
+
`#connection_removed` deleted only one on disconnect, leaving a stale entry
|
|
47
|
+
behind. Fixed by dropping the duplicate append.
|
|
48
|
+
|
|
49
|
+
|
|
3
50
|
## 0.23.0 — 2026-04-17
|
|
4
51
|
|
|
5
52
|
### Added
|
data/lib/omq/client_server.rb
CHANGED
|
@@ -5,7 +5,7 @@ module OMQ
|
|
|
5
5
|
# Owns the full arc of *one* connection: handshake → ready → closed.
|
|
6
6
|
#
|
|
7
7
|
# Scope boundary: ConnectionLifecycle tracks a single peer link
|
|
8
|
-
# (one ZMTP connection or one inproc
|
|
8
|
+
# (one ZMTP connection or one inproc Pipe). SocketLifecycle
|
|
9
9
|
# owns the socket-wide state above it — first-peer/last-peer
|
|
10
10
|
# signaling, reconnect enable flag, the parent task tree, and the
|
|
11
11
|
# open → closing → closed transitions that gate close-time drain.
|
|
@@ -43,7 +43,7 @@ module OMQ
|
|
|
43
43
|
}.freeze
|
|
44
44
|
|
|
45
45
|
|
|
46
|
-
# @return [Protocol::ZMTP::Connection, Transport::Inproc::
|
|
46
|
+
# @return [Protocol::ZMTP::Connection, Transport::Inproc::Pipe, nil]
|
|
47
47
|
attr_reader :conn
|
|
48
48
|
|
|
49
49
|
|
|
@@ -120,9 +120,9 @@ module OMQ
|
|
|
120
120
|
|
|
121
121
|
|
|
122
122
|
# Registers an already-connected inproc pipe as :ready.
|
|
123
|
-
# No handshake — inproc
|
|
123
|
+
# No handshake — inproc Pipe bypasses ZMTP entirely.
|
|
124
124
|
#
|
|
125
|
-
# @param pipe [Transport::Inproc::
|
|
125
|
+
# @param pipe [Transport::Inproc::Pipe]
|
|
126
126
|
#
|
|
127
127
|
def ready_direct!(pipe)
|
|
128
128
|
ready!(pipe)
|
|
@@ -161,7 +161,9 @@ module OMQ
|
|
|
161
161
|
|
|
162
162
|
|
|
163
163
|
def ready!(conn)
|
|
164
|
-
|
|
164
|
+
if @engine.connection_wrapper
|
|
165
|
+
conn = @engine.connection_wrapper.call(conn)
|
|
166
|
+
end
|
|
165
167
|
|
|
166
168
|
if @endpoint
|
|
167
169
|
transport_obj = @engine.transport_object_for(@endpoint)
|
|
@@ -177,7 +179,7 @@ module OMQ
|
|
|
177
179
|
@engine.peer_connected.resolve(@conn)
|
|
178
180
|
transition!(:ready)
|
|
179
181
|
|
|
180
|
-
# No supervisor if nothing to supervise: inproc
|
|
182
|
+
# No supervisor if nothing to supervise: inproc Pipes
|
|
181
183
|
# wire the recv/send paths synchronously (no task-based pumps),
|
|
182
184
|
# and isolated unit tests use a FakeEngine without pumps at all.
|
|
183
185
|
# Waiting on an empty barrier returns immediately and would
|
|
@@ -213,6 +215,7 @@ module OMQ
|
|
|
213
215
|
|
|
214
216
|
def tear_down!(reconnect:, reason: nil)
|
|
215
217
|
return if @state == :closed
|
|
218
|
+
|
|
216
219
|
transition!(:closed)
|
|
217
220
|
@engine.connections.delete(@conn)
|
|
218
221
|
@engine.routing.connection_removed(@conn) if @conn
|
|
@@ -244,11 +247,14 @@ module OMQ
|
|
|
244
247
|
|
|
245
248
|
def transition!(new_state)
|
|
246
249
|
allowed = TRANSITIONS[@state]
|
|
250
|
+
|
|
247
251
|
unless allowed&.include?(new_state)
|
|
248
252
|
raise InvalidTransition, "#{@state} → #{new_state}"
|
|
249
253
|
end
|
|
254
|
+
|
|
250
255
|
@state = new_state
|
|
251
256
|
end
|
|
257
|
+
|
|
252
258
|
end
|
|
253
259
|
end
|
|
254
260
|
end
|
data/lib/omq/engine/heartbeat.rb
CHANGED
data/lib/omq/engine/recv_pump.rb
CHANGED
|
@@ -4,7 +4,7 @@ module OMQ
|
|
|
4
4
|
class Engine
|
|
5
5
|
# Recv pump for a connection.
|
|
6
6
|
#
|
|
7
|
-
# For inproc
|
|
7
|
+
# For inproc Pipe: wires the direct recv path (no fiber spawned).
|
|
8
8
|
# For TCP/IPC: spawns a transient task that reads messages from the
|
|
9
9
|
# connection and enqueues them into +recv_queue+.
|
|
10
10
|
#
|
|
@@ -29,7 +29,7 @@ module OMQ
|
|
|
29
29
|
# Public entry point — callers use the class method.
|
|
30
30
|
#
|
|
31
31
|
# @param parent [Async::Task, Async::Barrier] parent to spawn under
|
|
32
|
-
# @param conn [Connection, Transport::Inproc::
|
|
32
|
+
# @param conn [Protocol::ZMTP::Connection, Transport::Inproc::Pipe]
|
|
33
33
|
# @param recv_queue [Async::LimitedQueue]
|
|
34
34
|
# @param engine [Engine]
|
|
35
35
|
# @param transform [Proc, nil]
|
|
@@ -40,7 +40,7 @@ module OMQ
|
|
|
40
40
|
end
|
|
41
41
|
|
|
42
42
|
|
|
43
|
-
# @param conn [Connection, Transport::Inproc::
|
|
43
|
+
# @param conn [Protocol::ZMTP::Connection, Transport::Inproc::Pipe]
|
|
44
44
|
# @param recv_queue [Async::LimitedQueue]
|
|
45
45
|
# @param engine [Engine]
|
|
46
46
|
#
|
|
@@ -52,7 +52,7 @@ module OMQ
|
|
|
52
52
|
end
|
|
53
53
|
|
|
54
54
|
|
|
55
|
-
# Starts the recv pump. For inproc
|
|
55
|
+
# Starts the recv pump. For inproc Pipe, wires the direct path
|
|
56
56
|
# (no task spawned). For TCP/IPC, spawns a fiber that reads messages.
|
|
57
57
|
#
|
|
58
58
|
# @param parent_task [Async::Task]
|
|
@@ -60,7 +60,7 @@ module OMQ
|
|
|
60
60
|
# @return [Async::Task, nil]
|
|
61
61
|
#
|
|
62
62
|
def start(parent_task, transform)
|
|
63
|
-
if @conn.is_a?(Transport::Inproc::
|
|
63
|
+
if @conn.is_a?(Transport::Inproc::Pipe) && @conn.peer
|
|
64
64
|
@conn.peer.wire_direct_recv(@recv_queue, transform)
|
|
65
65
|
return nil
|
|
66
66
|
end
|
|
@@ -72,6 +72,7 @@ module OMQ
|
|
|
72
72
|
end
|
|
73
73
|
end
|
|
74
74
|
|
|
75
|
+
|
|
75
76
|
private
|
|
76
77
|
|
|
77
78
|
|
|
@@ -93,7 +94,7 @@ module OMQ
|
|
|
93
94
|
|
|
94
95
|
while count < FAIRNESS_MESSAGES && bytes < FAIRNESS_BYTES
|
|
95
96
|
msg = conn.receive_message
|
|
96
|
-
msg = transform.call(msg)
|
|
97
|
+
msg = transform.call(msg)
|
|
97
98
|
|
|
98
99
|
# Emit the verbose trace BEFORE enqueueing so the monitor
|
|
99
100
|
# fiber is woken before the application fiber -- the
|
data/lib/omq/engine.rb
CHANGED
|
@@ -100,6 +100,7 @@ module OMQ
|
|
|
100
100
|
def parent_task = @lifecycle.parent_task
|
|
101
101
|
def barrier = @lifecycle.barrier
|
|
102
102
|
def closed? = @lifecycle.closed?
|
|
103
|
+
def on_io_thread? = @lifecycle.on_io_thread
|
|
103
104
|
|
|
104
105
|
|
|
105
106
|
# Enables or disables auto-reconnect for dropped connections.
|
|
@@ -280,10 +281,10 @@ module OMQ
|
|
|
280
281
|
end
|
|
281
282
|
|
|
282
283
|
|
|
283
|
-
# Called by inproc transport with a pre-validated
|
|
284
|
+
# Called by inproc transport with a pre-validated Pipe.
|
|
284
285
|
# Skips ZMTP handshake — just registers with routing strategy.
|
|
285
286
|
#
|
|
286
|
-
# @param pipe [Transport::Inproc::
|
|
287
|
+
# @param pipe [Transport::Inproc::Pipe]
|
|
287
288
|
# @return [void]
|
|
288
289
|
#
|
|
289
290
|
def connection_ready(pipe, endpoint: nil)
|
|
@@ -328,7 +329,7 @@ module OMQ
|
|
|
328
329
|
|
|
329
330
|
# Starts a recv pump for a connection, or wires the inproc fast path.
|
|
330
331
|
#
|
|
331
|
-
# @param conn [Connection, Transport::Inproc::
|
|
332
|
+
# @param conn [Protocol::ZMTP::Connection, Transport::Inproc::Pipe]
|
|
332
333
|
# @param recv_queue [Async::LimitedQueue]
|
|
333
334
|
# @yield [msg] optional per-message transform
|
|
334
335
|
# @return [Async::Task, nil]
|
|
@@ -345,7 +346,7 @@ module OMQ
|
|
|
345
346
|
|
|
346
347
|
# Called when a connection is lost.
|
|
347
348
|
#
|
|
348
|
-
# @param connection [Connection]
|
|
349
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
349
350
|
# @return [void]
|
|
350
351
|
#
|
|
351
352
|
def connection_lost(connection)
|
|
@@ -460,7 +461,7 @@ module OMQ
|
|
|
460
461
|
# pumps blocked on `dequeue` waiting for messages that will never
|
|
461
462
|
# be written.
|
|
462
463
|
#
|
|
463
|
-
# @param conn [Connection, Transport::Inproc::
|
|
464
|
+
# @param conn [Protocol::ZMTP::Connection, Transport::Inproc::Pipe]
|
|
464
465
|
# @param annotation [String]
|
|
465
466
|
#
|
|
466
467
|
def spawn_conn_pump_task(conn, annotation:, &block)
|
data/lib/omq/peer.rb
CHANGED
data/lib/omq/radio_dish.rb
CHANGED
data/lib/omq/readable.rb
CHANGED
|
@@ -14,7 +14,11 @@ module OMQ
|
|
|
14
14
|
# @raise [IO::TimeoutError] if read_timeout exceeded
|
|
15
15
|
#
|
|
16
16
|
def receive
|
|
17
|
-
|
|
17
|
+
if @engine.on_io_thread?
|
|
18
|
+
Reactor.run(timeout: @options.read_timeout) { @engine.dequeue_recv }
|
|
19
|
+
elsif (timeout = @options.read_timeout)
|
|
20
|
+
Async::Task.current.with_timeout(timeout, IO::TimeoutError) { @engine.dequeue_recv }
|
|
21
|
+
else
|
|
18
22
|
@engine.dequeue_recv
|
|
19
23
|
end
|
|
20
24
|
end
|
data/lib/omq/routing/channel.rb
CHANGED
|
@@ -39,7 +39,7 @@ module OMQ
|
|
|
39
39
|
end
|
|
40
40
|
|
|
41
41
|
|
|
42
|
-
# @param connection [Connection]
|
|
42
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
43
43
|
# @raise [RuntimeError] if a connection already exists
|
|
44
44
|
#
|
|
45
45
|
def connection_added(connection)
|
|
@@ -48,7 +48,7 @@ module OMQ
|
|
|
48
48
|
|
|
49
49
|
@engine.start_recv_pump(connection, @recv_queue)
|
|
50
50
|
|
|
51
|
-
unless connection.is_a?(Transport::Inproc::
|
|
51
|
+
unless connection.is_a?(Transport::Inproc::Pipe)
|
|
52
52
|
@send_queue = Routing.build_queue(@engine.options.send_hwm, :block)
|
|
53
53
|
while (msg = @staging_queue.dequeue(timeout: 0))
|
|
54
54
|
@send_queue.enqueue(msg)
|
|
@@ -58,7 +58,7 @@ module OMQ
|
|
|
58
58
|
end
|
|
59
59
|
|
|
60
60
|
|
|
61
|
-
# @param connection [Connection]
|
|
61
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
62
62
|
#
|
|
63
63
|
def connection_removed(connection)
|
|
64
64
|
if @connection == connection
|
|
@@ -72,7 +72,7 @@ module OMQ
|
|
|
72
72
|
#
|
|
73
73
|
def enqueue(parts)
|
|
74
74
|
conn = @connection
|
|
75
|
-
if conn.is_a?(Transport::Inproc::
|
|
75
|
+
if conn.is_a?(Transport::Inproc::Pipe) && conn.direct_recv_queue
|
|
76
76
|
conn.send_message(parts)
|
|
77
77
|
elsif @send_queue
|
|
78
78
|
@send_queue.enqueue(parts)
|
data/lib/omq/routing/client.rb
CHANGED
|
@@ -42,7 +42,7 @@ module OMQ
|
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
|
|
45
|
-
# @param connection [Connection]
|
|
45
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
46
46
|
#
|
|
47
47
|
def connection_added(connection)
|
|
48
48
|
@connections << connection
|
|
@@ -51,7 +51,7 @@ module OMQ
|
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
|
|
54
|
-
# @param connection [Connection]
|
|
54
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
55
55
|
#
|
|
56
56
|
def connection_removed(connection)
|
|
57
57
|
@connections.delete(connection)
|
data/lib/omq/routing/dealer.rb
CHANGED
|
@@ -42,7 +42,7 @@ module OMQ
|
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
|
|
45
|
-
# @param connection [Connection]
|
|
45
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
46
46
|
#
|
|
47
47
|
def connection_added(connection)
|
|
48
48
|
@engine.start_recv_pump(connection, @recv_queue)
|
|
@@ -50,7 +50,7 @@ module OMQ
|
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
|
|
53
|
-
# @param connection [Connection]
|
|
53
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
54
54
|
#
|
|
55
55
|
def connection_removed(connection)
|
|
56
56
|
@connections.delete(connection)
|
data/lib/omq/routing/dish.rb
CHANGED
|
@@ -41,7 +41,7 @@ module OMQ
|
|
|
41
41
|
end
|
|
42
42
|
|
|
43
43
|
|
|
44
|
-
# @param connection [Connection]
|
|
44
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
45
45
|
#
|
|
46
46
|
def connection_added(connection)
|
|
47
47
|
@connections << connection
|
|
@@ -52,7 +52,7 @@ module OMQ
|
|
|
52
52
|
end
|
|
53
53
|
|
|
54
54
|
|
|
55
|
-
# @param connection [Connection]
|
|
55
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
56
56
|
#
|
|
57
57
|
def connection_removed(connection)
|
|
58
58
|
@connections.delete(connection)
|
data/lib/omq/routing/fan_out.rb
CHANGED
|
@@ -61,7 +61,7 @@ module OMQ
|
|
|
61
61
|
# Override in subclasses to expose subscriptions to the
|
|
62
62
|
# application (e.g. XPUB enqueues to recv_queue).
|
|
63
63
|
#
|
|
64
|
-
# @param conn [Connection]
|
|
64
|
+
# @param conn [Protocol::ZMTP::Connection]
|
|
65
65
|
# @param prefix [String]
|
|
66
66
|
#
|
|
67
67
|
def on_subscribe(conn, prefix)
|
|
@@ -74,7 +74,7 @@ module OMQ
|
|
|
74
74
|
# Called when a cancel command is received from a peer.
|
|
75
75
|
# Override in subclasses (e.g. XPUB enqueues to recv_queue).
|
|
76
76
|
#
|
|
77
|
-
# @param conn [Connection]
|
|
77
|
+
# @param conn [Protocol::ZMTP::Connection]
|
|
78
78
|
# @param prefix [String]
|
|
79
79
|
#
|
|
80
80
|
def on_cancel(conn, prefix)
|
|
@@ -86,7 +86,7 @@ module OMQ
|
|
|
86
86
|
# Creates a per-connection send queue and starts its send pump.
|
|
87
87
|
# Call from #connection_added.
|
|
88
88
|
#
|
|
89
|
-
# @param conn [Connection]
|
|
89
|
+
# @param conn [Protocol::ZMTP::Connection]
|
|
90
90
|
#
|
|
91
91
|
def add_fan_out_send_connection(conn)
|
|
92
92
|
q = Routing.build_queue(@engine.options.send_hwm, @engine.options.on_mute)
|
|
@@ -99,7 +99,7 @@ module OMQ
|
|
|
99
99
|
# down by the per-connection lifecycle barrier.
|
|
100
100
|
# Call from #connection_removed.
|
|
101
101
|
#
|
|
102
|
-
# @param conn [Connection]
|
|
102
|
+
# @param conn [Protocol::ZMTP::Connection]
|
|
103
103
|
#
|
|
104
104
|
def remove_fan_out_send_connection(conn)
|
|
105
105
|
@subscribe_all.delete(conn)
|
|
@@ -152,7 +152,7 @@ module OMQ
|
|
|
152
152
|
# In conflate mode, drains the batch and keeps only the latest
|
|
153
153
|
# message per topic before writing.
|
|
154
154
|
#
|
|
155
|
-
# @param conn [Connection]
|
|
155
|
+
# @param conn [Protocol::ZMTP::Connection]
|
|
156
156
|
# @param q [Async::LimitedQueue, DropQueue]
|
|
157
157
|
#
|
|
158
158
|
def start_conn_send_pump(conn, q)
|
|
@@ -169,7 +169,7 @@ module OMQ
|
|
|
169
169
|
# Send pump variant for non-conflate fan-out: dequeues, batch-drains,
|
|
170
170
|
# writes each subscribed message, then flushes once.
|
|
171
171
|
#
|
|
172
|
-
# @param conn [Connection]
|
|
172
|
+
# @param conn [Protocol::ZMTP::Connection]
|
|
173
173
|
# @param q [Async::LimitedQueue, DropQueue]
|
|
174
174
|
# @param use_wire [Boolean] true iff the encoded wire bytes can
|
|
175
175
|
# be shared across peers (unencrypted ZMTP)
|
|
@@ -219,7 +219,7 @@ module OMQ
|
|
|
219
219
|
# Send pump variant for conflate mode: keeps only the latest
|
|
220
220
|
# subscribed message per batch. Stale duplicates are dropped.
|
|
221
221
|
#
|
|
222
|
-
# @param conn [Connection]
|
|
222
|
+
# @param conn [Protocol::ZMTP::Connection]
|
|
223
223
|
# @param q [Async::LimitedQueue, DropQueue]
|
|
224
224
|
# @return [Async::Task]
|
|
225
225
|
#
|
data/lib/omq/routing/gather.rb
CHANGED
|
@@ -36,14 +36,14 @@ module OMQ
|
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
|
|
39
|
-
# @param connection [Connection]
|
|
39
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
40
40
|
#
|
|
41
41
|
def connection_added(connection)
|
|
42
42
|
@engine.start_recv_pump(connection, @recv_queue)
|
|
43
43
|
end
|
|
44
44
|
|
|
45
45
|
|
|
46
|
-
# @param connection [Connection]
|
|
46
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
47
47
|
#
|
|
48
48
|
def connection_removed(connection)
|
|
49
49
|
end
|
data/lib/omq/routing/pair.rb
CHANGED
|
@@ -43,7 +43,7 @@ module OMQ
|
|
|
43
43
|
end
|
|
44
44
|
|
|
45
45
|
|
|
46
|
-
# @param connection [Connection]
|
|
46
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
47
47
|
# @raise [RuntimeError] if a connection already exists
|
|
48
48
|
#
|
|
49
49
|
def connection_added(connection)
|
|
@@ -52,13 +52,13 @@ module OMQ
|
|
|
52
52
|
|
|
53
53
|
@engine.start_recv_pump(connection, @recv_queue)
|
|
54
54
|
|
|
55
|
-
unless connection.is_a?(Transport::Inproc::
|
|
55
|
+
unless connection.is_a?(Transport::Inproc::Pipe)
|
|
56
56
|
start_send_pump(connection)
|
|
57
57
|
end
|
|
58
58
|
end
|
|
59
59
|
|
|
60
60
|
|
|
61
|
-
# @param connection [Connection]
|
|
61
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
62
62
|
#
|
|
63
63
|
def connection_removed(connection)
|
|
64
64
|
@connection = nil if @connection == connection
|
|
@@ -69,7 +69,7 @@ module OMQ
|
|
|
69
69
|
#
|
|
70
70
|
def enqueue(parts)
|
|
71
71
|
conn = @connection
|
|
72
|
-
if conn.is_a?(Transport::Inproc::
|
|
72
|
+
if conn.is_a?(Transport::Inproc::Pipe) && conn.direct_recv_queue
|
|
73
73
|
conn.send_message(parts)
|
|
74
74
|
else
|
|
75
75
|
@send_queue.enqueue(parts)
|
data/lib/omq/routing/peer.rb
CHANGED
|
@@ -50,7 +50,7 @@ module OMQ
|
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
|
|
53
|
-
# @param connection [Connection]
|
|
53
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
54
54
|
#
|
|
55
55
|
def connection_added(connection)
|
|
56
56
|
routing_id = SecureRandom.bytes(4)
|
|
@@ -65,7 +65,7 @@ module OMQ
|
|
|
65
65
|
end
|
|
66
66
|
|
|
67
67
|
|
|
68
|
-
# @param connection [Connection]
|
|
68
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
69
69
|
#
|
|
70
70
|
def connection_removed(connection)
|
|
71
71
|
routing_id = @routing_id_by_connection.delete(connection)
|
data/lib/omq/routing/pub.rb
CHANGED
|
@@ -36,7 +36,7 @@ module OMQ
|
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
|
|
39
|
-
# @param connection [Connection]
|
|
39
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
40
40
|
#
|
|
41
41
|
def connection_added(connection)
|
|
42
42
|
@connections << connection
|
|
@@ -46,7 +46,7 @@ module OMQ
|
|
|
46
46
|
end
|
|
47
47
|
|
|
48
48
|
|
|
49
|
-
# @param connection [Connection]
|
|
49
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
50
50
|
#
|
|
51
51
|
def connection_removed(connection)
|
|
52
52
|
@connections.delete(connection)
|
data/lib/omq/routing/pull.rb
CHANGED
|
@@ -38,14 +38,14 @@ module OMQ
|
|
|
38
38
|
end
|
|
39
39
|
|
|
40
40
|
|
|
41
|
-
# @param connection [Connection]
|
|
41
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
42
42
|
#
|
|
43
43
|
def connection_added(connection)
|
|
44
44
|
@engine.start_recv_pump(connection, @recv_queue)
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
|
|
48
|
-
# @param connection [Connection]
|
|
48
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
49
49
|
#
|
|
50
50
|
def connection_removed(connection)
|
|
51
51
|
# recv pump stops on EOFError via its connection barrier
|
data/lib/omq/routing/push.rb
CHANGED
|
@@ -33,7 +33,7 @@ module OMQ
|
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
|
|
36
|
-
# @param connection [Connection]
|
|
36
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
37
37
|
#
|
|
38
38
|
def connection_added(connection)
|
|
39
39
|
add_round_robin_send_connection(connection)
|
|
@@ -41,7 +41,7 @@ module OMQ
|
|
|
41
41
|
end
|
|
42
42
|
|
|
43
43
|
|
|
44
|
-
# @param connection [Connection]
|
|
44
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
45
45
|
#
|
|
46
46
|
def connection_removed(connection)
|
|
47
47
|
@connections.delete(connection)
|
|
@@ -64,7 +64,7 @@ module OMQ
|
|
|
64
64
|
# may succeed if the kernel send buffer absorbs the data.
|
|
65
65
|
#
|
|
66
66
|
def start_reaper(conn)
|
|
67
|
-
return if conn.is_a?(Transport::Inproc::
|
|
67
|
+
return if conn.is_a?(Transport::Inproc::Pipe)
|
|
68
68
|
@engine.spawn_conn_pump_task(conn, annotation: "reaper") do
|
|
69
69
|
conn.receive_message # blocks until peer disconnects; then exits
|
|
70
70
|
end
|
data/lib/omq/routing/radio.rb
CHANGED
|
@@ -50,7 +50,7 @@ module OMQ
|
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
|
|
53
|
-
# @param connection [Connection]
|
|
53
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
54
54
|
#
|
|
55
55
|
def connection_added(connection)
|
|
56
56
|
@connections << connection
|
|
@@ -64,7 +64,7 @@ module OMQ
|
|
|
64
64
|
end
|
|
65
65
|
|
|
66
66
|
|
|
67
|
-
# @param connection [Connection]
|
|
67
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
68
68
|
#
|
|
69
69
|
def connection_removed(connection)
|
|
70
70
|
@connections.delete(connection)
|
data/lib/omq/routing/rep.rb
CHANGED
|
@@ -45,7 +45,7 @@ module OMQ
|
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
|
|
48
|
-
# @param connection [Connection]
|
|
48
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
49
49
|
#
|
|
50
50
|
def connection_added(connection)
|
|
51
51
|
@engine.start_recv_pump(connection, @recv_queue) do |msg|
|
|
@@ -63,7 +63,7 @@ module OMQ
|
|
|
63
63
|
end
|
|
64
64
|
|
|
65
65
|
|
|
66
|
-
# @param connection [Connection]
|
|
66
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
67
67
|
#
|
|
68
68
|
def connection_removed(connection)
|
|
69
69
|
@pending_replies.reject! { |r| r[0] == connection }
|
data/lib/omq/routing/req.rb
CHANGED
|
@@ -46,7 +46,7 @@ module OMQ
|
|
|
46
46
|
end
|
|
47
47
|
|
|
48
48
|
|
|
49
|
-
# @param connection [Connection]
|
|
49
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
50
50
|
#
|
|
51
51
|
def connection_added(connection)
|
|
52
52
|
@engine.start_recv_pump(connection, @recv_queue) do |msg|
|
|
@@ -58,7 +58,7 @@ module OMQ
|
|
|
58
58
|
end
|
|
59
59
|
|
|
60
60
|
|
|
61
|
-
# @param connection [Connection]
|
|
61
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
62
62
|
#
|
|
63
63
|
def connection_removed(connection)
|
|
64
64
|
@connections.delete(connection)
|
|
@@ -48,7 +48,7 @@ module OMQ
|
|
|
48
48
|
# Registers a connection and starts its send pump.
|
|
49
49
|
# Call from #connection_added.
|
|
50
50
|
#
|
|
51
|
-
# @param conn [Connection]
|
|
51
|
+
# @param conn [Protocol::ZMTP::Connection]
|
|
52
52
|
#
|
|
53
53
|
def add_round_robin_send_connection(conn)
|
|
54
54
|
@connections << conn
|
|
@@ -63,7 +63,7 @@ module OMQ
|
|
|
63
63
|
# guarantee, so this is safe. The pump itself is torn down by
|
|
64
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
|
|
@@ -73,7 +73,7 @@ module OMQ
|
|
|
73
73
|
# Updates the direct-pipe shortcut for inproc single-peer bypass.
|
|
74
74
|
#
|
|
75
75
|
def update_direct_pipe
|
|
76
|
-
if @connections.size == 1 && @connections.first.is_a?(Transport::Inproc::
|
|
76
|
+
if @connections.size == 1 && @connections.first.is_a?(Transport::Inproc::Pipe)
|
|
77
77
|
@direct_pipe = @connections.first
|
|
78
78
|
else
|
|
79
79
|
@direct_pipe = nil
|
|
@@ -128,7 +128,7 @@ module OMQ
|
|
|
128
128
|
# run. The yield is effectively free when the scheduler has no
|
|
129
129
|
# other work.
|
|
130
130
|
#
|
|
131
|
-
# @param conn [Connection]
|
|
131
|
+
# @param conn [Protocol::ZMTP::Connection]
|
|
132
132
|
#
|
|
133
133
|
def start_conn_send_pump(conn)
|
|
134
134
|
@engine.spawn_conn_pump_task(conn, annotation: "send pump") do
|
data/lib/omq/routing/router.rb
CHANGED
|
@@ -45,7 +45,7 @@ module OMQ
|
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
|
|
48
|
-
# @param connection [Connection]
|
|
48
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
49
49
|
#
|
|
50
50
|
def connection_added(connection)
|
|
51
51
|
identity = connection.peer_identity
|
|
@@ -61,7 +61,7 @@ module OMQ
|
|
|
61
61
|
end
|
|
62
62
|
|
|
63
63
|
|
|
64
|
-
# @param connection [Connection]
|
|
64
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
65
65
|
#
|
|
66
66
|
def connection_removed(connection)
|
|
67
67
|
identity = @identity_by_connection.delete(connection)
|
data/lib/omq/routing/scatter.rb
CHANGED
|
@@ -33,16 +33,15 @@ module OMQ
|
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
|
|
36
|
-
# @param connection [Connection]
|
|
36
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
37
37
|
#
|
|
38
38
|
def connection_added(connection)
|
|
39
|
-
@connections << connection
|
|
40
39
|
add_round_robin_send_connection(connection)
|
|
41
40
|
start_reaper(connection)
|
|
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)
|
|
@@ -63,10 +62,10 @@ module OMQ
|
|
|
63
62
|
# Detects peer disconnection on write-only sockets by
|
|
64
63
|
# blocking on a receive that only returns on disconnect.
|
|
65
64
|
#
|
|
66
|
-
# @param conn [Connection]
|
|
65
|
+
# @param conn [Protocol::ZMTP::Connection]
|
|
67
66
|
#
|
|
68
67
|
def start_reaper(conn)
|
|
69
|
-
return if conn.is_a?(Transport::Inproc::
|
|
68
|
+
return if conn.is_a?(Transport::Inproc::Pipe)
|
|
70
69
|
@engine.spawn_conn_pump_task(conn, annotation: "reaper") do
|
|
71
70
|
conn.receive_message # blocks until peer disconnects; then exits
|
|
72
71
|
end
|
data/lib/omq/routing/server.rb
CHANGED
|
@@ -45,7 +45,7 @@ module OMQ
|
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
|
|
48
|
-
# @param connection [Connection]
|
|
48
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
49
49
|
#
|
|
50
50
|
def connection_added(connection)
|
|
51
51
|
routing_id = SecureRandom.bytes(4)
|
|
@@ -60,7 +60,7 @@ module OMQ
|
|
|
60
60
|
end
|
|
61
61
|
|
|
62
62
|
|
|
63
|
-
# @param connection [Connection]
|
|
63
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
64
64
|
#
|
|
65
65
|
def connection_removed(connection)
|
|
66
66
|
routing_id = @routing_id_by_connection.delete(connection)
|
data/lib/omq/routing/sub.rb
CHANGED
|
@@ -41,7 +41,7 @@ module OMQ
|
|
|
41
41
|
end
|
|
42
42
|
|
|
43
43
|
|
|
44
|
-
# @param connection [Connection]
|
|
44
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
45
45
|
#
|
|
46
46
|
def connection_added(connection)
|
|
47
47
|
@connections << connection
|
|
@@ -54,7 +54,7 @@ module OMQ
|
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
|
|
57
|
-
# @param connection [Connection]
|
|
57
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
58
58
|
#
|
|
59
59
|
def connection_removed(connection)
|
|
60
60
|
@connections.delete(connection)
|
data/lib/omq/routing/xpub.rb
CHANGED
|
@@ -41,7 +41,7 @@ module OMQ
|
|
|
41
41
|
end
|
|
42
42
|
|
|
43
43
|
|
|
44
|
-
# @param connection [Connection]
|
|
44
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
45
45
|
#
|
|
46
46
|
def connection_added(connection)
|
|
47
47
|
@connections << connection
|
|
@@ -51,7 +51,7 @@ module OMQ
|
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
|
|
54
|
-
# @param connection [Connection]
|
|
54
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
55
55
|
#
|
|
56
56
|
def connection_removed(connection)
|
|
57
57
|
@connections.delete(connection)
|
data/lib/omq/routing/xsub.rb
CHANGED
|
@@ -43,7 +43,7 @@ module OMQ
|
|
|
43
43
|
end
|
|
44
44
|
|
|
45
45
|
|
|
46
|
-
# @param connection [Connection]
|
|
46
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
47
47
|
#
|
|
48
48
|
def connection_added(connection)
|
|
49
49
|
@connections << connection
|
|
@@ -56,7 +56,7 @@ module OMQ
|
|
|
56
56
|
end
|
|
57
57
|
|
|
58
58
|
|
|
59
|
-
# @param connection [Connection]
|
|
59
|
+
# @param connection [Protocol::ZMTP::Connection]
|
|
60
60
|
#
|
|
61
61
|
def connection_removed(connection)
|
|
62
62
|
@connections.delete(connection)
|
|
@@ -14,7 +14,7 @@ module OMQ
|
|
|
14
14
|
# This reduces inproc from 3 queue hops to 2 (send_queue →
|
|
15
15
|
# recv_queue), eliminating the internal pipe queue in between.
|
|
16
16
|
#
|
|
17
|
-
class
|
|
17
|
+
class Pipe
|
|
18
18
|
# @return [String] peer's socket type
|
|
19
19
|
#
|
|
20
20
|
attr_reader :peer_socket_type
|
|
@@ -39,7 +39,7 @@ module OMQ
|
|
|
39
39
|
attr_reader :peer_identity
|
|
40
40
|
|
|
41
41
|
|
|
42
|
-
# @return [
|
|
42
|
+
# @return [Pipe, nil] the other end of this pipe pair
|
|
43
43
|
#
|
|
44
44
|
attr_accessor :peer
|
|
45
45
|
|
|
@@ -85,6 +85,7 @@ module OMQ
|
|
|
85
85
|
def wire_direct_recv(queue, transform)
|
|
86
86
|
@direct_recv_transform = transform
|
|
87
87
|
@direct_recv_queue = queue
|
|
88
|
+
|
|
88
89
|
return unless @pending_direct
|
|
89
90
|
|
|
90
91
|
@pending_direct.each { |msg| queue.enqueue(msg) }
|
|
@@ -99,6 +100,7 @@ module OMQ
|
|
|
99
100
|
#
|
|
100
101
|
def send_message(parts)
|
|
101
102
|
raise IOError, "closed" if @closed
|
|
103
|
+
|
|
102
104
|
if @direct_recv_queue
|
|
103
105
|
@direct_recv_queue.enqueue(apply_transform(parts))
|
|
104
106
|
elsif @send_queue
|
|
@@ -114,7 +116,7 @@ module OMQ
|
|
|
114
116
|
|
|
115
117
|
# Batched form, for parity with Protocol::ZMTP::Connection. The
|
|
116
118
|
# work-stealing pumps call this when they dequeue more than one
|
|
117
|
-
# message at once;
|
|
119
|
+
# message at once; Pipe just loops — no mutex to amortize.
|
|
118
120
|
#
|
|
119
121
|
# @param messages [Array<Array<String>>]
|
|
120
122
|
# @return [void]
|
|
@@ -147,14 +149,13 @@ module OMQ
|
|
|
147
149
|
#
|
|
148
150
|
def receive_message
|
|
149
151
|
loop do
|
|
150
|
-
item = @receive_queue.dequeue
|
|
151
|
-
|
|
152
|
-
raise EOFError, "connection closed" if item.nil?
|
|
152
|
+
item = @receive_queue.dequeue or raise EOFError, "connection closed"
|
|
153
153
|
|
|
154
154
|
if item.is_a?(Array) && item.first == :command
|
|
155
155
|
if block_given?
|
|
156
156
|
yield Protocol::ZMTP::Codec::Frame.new(item[1].to_body, command: true)
|
|
157
157
|
end
|
|
158
|
+
|
|
158
159
|
next
|
|
159
160
|
end
|
|
160
161
|
|
|
@@ -181,8 +182,7 @@ module OMQ
|
|
|
181
182
|
# @return [Protocol::ZMTP::Codec::Frame]
|
|
182
183
|
#
|
|
183
184
|
def read_frame
|
|
184
|
-
item = @receive_queue.dequeue
|
|
185
|
-
raise EOFError, "connection closed" if item.nil?
|
|
185
|
+
item = @receive_queue.dequeue or raise EOFError, "connection closed"
|
|
186
186
|
|
|
187
187
|
if item.is_a?(Array) && item.first == :command
|
|
188
188
|
Protocol::ZMTP::Codec::Frame.new(item[1].to_body, command: true)
|
|
@@ -208,7 +208,7 @@ module OMQ
|
|
|
208
208
|
|
|
209
209
|
def apply_transform(parts)
|
|
210
210
|
if @direct_recv_transform
|
|
211
|
-
@direct_recv_transform.call(parts)
|
|
211
|
+
@direct_recv_transform.call(parts)
|
|
212
212
|
else
|
|
213
213
|
parts
|
|
214
214
|
end
|
data/lib/omq/transport/inproc.rb
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require "async"
|
|
4
4
|
require "async/queue"
|
|
5
|
-
require_relative "inproc/
|
|
5
|
+
require_relative "inproc/pipe"
|
|
6
6
|
|
|
7
7
|
module OMQ
|
|
8
8
|
module Transport
|
|
@@ -122,8 +122,8 @@ module OMQ
|
|
|
122
122
|
end
|
|
123
123
|
|
|
124
124
|
|
|
125
|
-
# Decides whether a
|
|
126
|
-
#
|
|
125
|
+
# Decides whether a Pipe pair needs command queues.
|
|
126
|
+
# Pipe's fast path skips queues entirely; command queues
|
|
127
127
|
# are only needed for socket types that exchange ZMTP commands
|
|
128
128
|
# (e.g. ROUTER/DEALER identity, PUB/SUB subscriptions) or when
|
|
129
129
|
# either side enables QoS ≥ 1.
|
|
@@ -137,11 +137,11 @@ module OMQ
|
|
|
137
137
|
end
|
|
138
138
|
|
|
139
139
|
|
|
140
|
-
# Builds a bidirectional {
|
|
140
|
+
# Builds a bidirectional {Pipe} pair for client + server.
|
|
141
141
|
# When +needs_cmds+ is false the pipes have no command queues
|
|
142
142
|
# (fast path — all traffic bypasses Async::Queue entirely).
|
|
143
143
|
#
|
|
144
|
-
# @return [Array(
|
|
144
|
+
# @return [Array(Pipe, Pipe)] client, server
|
|
145
145
|
#
|
|
146
146
|
def make_pipe_pair(ce, se, ct, st, needs_cmds)
|
|
147
147
|
if needs_cmds
|
|
@@ -149,12 +149,12 @@ module OMQ
|
|
|
149
149
|
b_to_a = Async::Queue.new
|
|
150
150
|
end
|
|
151
151
|
|
|
152
|
-
client =
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
server =
|
|
156
|
-
|
|
157
|
-
|
|
152
|
+
client = Pipe.new(send_queue: needs_cmds ? a_to_b : nil,
|
|
153
|
+
receive_queue: needs_cmds ? b_to_a : nil,
|
|
154
|
+
peer_identity: se.options.identity, peer_type: st.to_s)
|
|
155
|
+
server = Pipe.new(send_queue: needs_cmds ? b_to_a : nil,
|
|
156
|
+
receive_queue: needs_cmds ? a_to_b : nil,
|
|
157
|
+
peer_identity: ce.options.identity, peer_type: ct.to_s)
|
|
158
158
|
|
|
159
159
|
client.peer = server
|
|
160
160
|
server.peer = client
|
data/lib/omq/transport/udp.rb
CHANGED
data/lib/omq/version.rb
CHANGED
data/lib/omq/writable.rb
CHANGED
|
@@ -9,19 +9,25 @@ module OMQ
|
|
|
9
9
|
include QueueWritable
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
EMPTY_PART = "".b.freeze
|
|
13
|
-
|
|
14
|
-
|
|
15
12
|
# Sends a message.
|
|
16
13
|
#
|
|
14
|
+
# Caller owns the message parts. Don't mutate them after sending — especially
|
|
15
|
+
# with inproc transport or PUB fan-out, where a single reference can be shared
|
|
16
|
+
# across peers and read later by the send pump.
|
|
17
|
+
#
|
|
17
18
|
# @param message [String, Array<String>] message parts
|
|
18
19
|
# @return [self]
|
|
19
20
|
# @raise [IO::TimeoutError] if write_timeout exceeded
|
|
20
21
|
#
|
|
21
22
|
def send(message)
|
|
22
|
-
parts =
|
|
23
|
+
parts = message.is_a?(Array) ? message : [message]
|
|
24
|
+
raise ArgumentError, "message has no parts" if parts.empty?
|
|
23
25
|
|
|
24
|
-
|
|
26
|
+
if @engine.on_io_thread?
|
|
27
|
+
Reactor.run(timeout: @options.write_timeout) { @engine.enqueue_send(parts) }
|
|
28
|
+
elsif (timeout = @options.write_timeout)
|
|
29
|
+
Async::Task.current.with_timeout(timeout, IO::TimeoutError) { @engine.enqueue_send(parts) }
|
|
30
|
+
else
|
|
25
31
|
@engine.enqueue_send(parts)
|
|
26
32
|
end
|
|
27
33
|
|
|
@@ -48,42 +54,5 @@ module OMQ
|
|
|
48
54
|
true
|
|
49
55
|
end
|
|
50
56
|
|
|
51
|
-
|
|
52
|
-
private
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
# Converts a message into a frozen array of frozen binary strings.
|
|
56
|
-
#
|
|
57
|
-
# @param message [String, Array<String>]
|
|
58
|
-
# @return [Array<String>] frozen array of frozen binary strings
|
|
59
|
-
#
|
|
60
|
-
def freeze_message(message)
|
|
61
|
-
parts = message.is_a?(Array) ? message : [message]
|
|
62
|
-
raise ArgumentError, "message has no parts" if parts.empty?
|
|
63
|
-
|
|
64
|
-
all_ready = parts.all? { |p| p.is_a?(String) && p.frozen? && p.encoding == Encoding::BINARY }
|
|
65
|
-
|
|
66
|
-
# Already a frozen array of frozen binary strings → return as-is.
|
|
67
|
-
return parts if all_ready && parts.frozen?
|
|
68
|
-
|
|
69
|
-
# Items are ready; just freeze the outer array.
|
|
70
|
-
return parts.freeze if all_ready
|
|
71
|
-
|
|
72
|
-
# Items need conversion. Mutate in place when we can.
|
|
73
|
-
if parts.frozen?
|
|
74
|
-
parts.map { |p| frozen_binary(p) }.freeze
|
|
75
|
-
else
|
|
76
|
-
parts.map! { |p| frozen_binary(p) }.freeze
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
def frozen_binary(obj)
|
|
82
|
-
return EMPTY_PART if obj.nil?
|
|
83
|
-
s = obj.to_s
|
|
84
|
-
return s if s.frozen? && s.encoding == Encoding::BINARY
|
|
85
|
-
s.b.freeze
|
|
86
|
-
end
|
|
87
|
-
|
|
88
57
|
end
|
|
89
58
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: omq
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.24.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Patrik Wenger
|
|
@@ -114,7 +114,7 @@ files:
|
|
|
114
114
|
- lib/omq/single_frame.rb
|
|
115
115
|
- lib/omq/socket.rb
|
|
116
116
|
- lib/omq/transport/inproc.rb
|
|
117
|
-
- lib/omq/transport/inproc/
|
|
117
|
+
- lib/omq/transport/inproc/pipe.rb
|
|
118
118
|
- lib/omq/transport/ipc.rb
|
|
119
119
|
- lib/omq/transport/tcp.rb
|
|
120
120
|
- lib/omq/transport/udp.rb
|