omq 0.22.0 → 0.22.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: aa0683eef1c05982186c434cfbb21112518ec220e843207fa772a3cc3cd69ee9
4
- data.tar.gz: 95b92509cac850c9b45380675fec60ed3db22cc21674ffde09901742b024f43a
3
+ metadata.gz: f58b9e0c8c49bcdfb8dd80ec5eda6a6b6e5b09f04a2a7851001449449ba448fd
4
+ data.tar.gz: 0f6cbd451adc8b1d1cde0771d6535c5959f09e4b3f0442164b0544964755795e
5
5
  SHA512:
6
- metadata.gz: 51b018f6e6d0fe83181e14fefc9f7cda13661cc3e071e2b83f2ed517e98e550eb22f9c7b7092696261ce4bd458a7355ccfe51cb44235c38df9004f6c72d7c31b
7
- data.tar.gz: 7e4581c1f0e18714a30af54833d6cabef1001936d5f4126bde2fa6144dfe3b153b825dff82576a7abca0d61dc9f87b01f0a962f950c56c2d0a5803705addf1ca
6
+ metadata.gz: d7d13f97eeacf998f1e0137bdbc5dd4a471195ff628fd7da97720a019e30c2a9c200fab761c38943bbbada056bf81880e6ca2dd87d3936f150f0fa22566cebe5
7
+ data.tar.gz: f97931ecb4893ecd0155c37ea18793c9414bd57de6918496ef7af18bad714720aa2e146531788956265d6f85bc3e18f6dd403f71df8683913d322c94a6dd1bdb
data/CHANGELOG.md CHANGED
@@ -1,5 +1,29 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.22.1 — 2026-04-16
4
+
5
+ ### Changed
6
+
7
+ - **Reuse batch arrays in send pumps.** All send pumps (RoundRobin,
8
+ Pair, ConnSendPump, FanOut, FanOut-conflate) now pre-allocate a
9
+ single batch array and clear it between cycles instead of
10
+ allocating a fresh `[msg]` per dequeue.
11
+
12
+ - **`Routing.dequeue_batch`** consolidates the blocking-dequeue +
13
+ non-blocking-sweep pattern that was duplicated across four call
14
+ sites into one method. `dequeue_batch_capped` does the same for
15
+ the byte/message-capped RoundRobin variant.
16
+
17
+ - **REP envelope stored as `[conn, envelope]`** instead of a Hash,
18
+ and reply assembly uses `<<` + `concat` instead of double splat.
19
+
20
+ - **Heartbeat drops redundant `context: "".b`** — the default is
21
+ now `EMPTY_BINARY` in protocol-zmtp.
22
+
23
+ - **Bench harness accepts `OMQ_BENCH_SIZES`, `OMQ_BENCH_TRANSPORTS`,
24
+ and `OMQ_BENCH_PEERS`** env vars to scope runs without editing
25
+ code.
26
+
3
27
  ## 0.22.0 — 2026-04-15
4
28
 
5
29
  ### Fixed
@@ -24,7 +24,7 @@ module OMQ
24
24
  tasks << parent.async(transient: true, annotation: "heartbeat") do
25
25
  loop do
26
26
  sleep interval
27
- conn.send_command(Protocol::ZMTP::Codec::Command.ping(ttl: ttl, context: "".b))
27
+ conn.send_command(Protocol::ZMTP::Codec::Command.ping(ttl: ttl))
28
28
  if conn.heartbeat_expired?(timeout)
29
29
  conn.close
30
30
  break
@@ -18,9 +18,10 @@ module OMQ
18
18
  #
19
19
  def self.start(engine, conn, q, tasks)
20
20
  task = engine.spawn_conn_pump_task(conn, annotation: "send pump") do
21
+ batch = []
22
+
21
23
  loop do
22
- batch = [q.dequeue]
23
- Routing.drain_send_queue(q, batch)
24
+ Routing.dequeue_batch(q, batch)
24
25
 
25
26
  if batch.size == 1
26
27
  conn.write_message batch.first
@@ -30,7 +31,11 @@ module OMQ
30
31
 
31
32
  conn.flush
32
33
 
33
- batch.each { |parts| engine.emit_verbose_msg_sent(conn, parts) }
34
+ batch.each do |parts|
35
+ engine.emit_verbose_msg_sent(conn, parts)
36
+ end
37
+
38
+ batch.clear
34
39
  end
35
40
  end
36
41
 
@@ -181,14 +181,16 @@ module OMQ
181
181
  #
182
182
  def start_conn_send_pump_normal(conn, q, use_wire)
183
183
  @engine.spawn_conn_pump_task(conn, annotation: "send pump") do
184
+ batch = []
185
+
184
186
  loop do
185
- batch = [q.dequeue]
186
- Routing.drain_send_queue(q, batch)
187
+ Routing.dequeue_batch(q, batch)
187
188
 
188
189
  if write_matching_batch(conn, batch, use_wire)
189
190
  conn.flush
190
191
  batch.each { |parts| @engine.emit_verbose_msg_sent(conn, parts) }
191
192
  end
193
+ batch.clear
192
194
  end
193
195
  end
194
196
  end
@@ -227,14 +229,17 @@ module OMQ
227
229
  #
228
230
  def start_conn_send_pump_conflate(conn, q)
229
231
  @engine.spawn_conn_pump_task(conn, annotation: "send pump") do
232
+ batch = []
233
+
230
234
  loop do
231
- batch = [q.dequeue]
232
- Routing.drain_send_queue(q, batch)
235
+ Routing.dequeue_batch(q, batch)
233
236
 
234
237
  # Keep only the latest message that matches the subscription.
235
238
  latest = batch.reverse.find do |parts|
236
239
  subscribed?(conn, parts.first || EMPTY_BINARY)
237
240
  end
241
+
242
+ batch.clear
238
243
  next unless latest
239
244
 
240
245
  conn.write_message(latest)
@@ -106,9 +106,10 @@ module OMQ
106
106
 
107
107
  def start_send_pump(conn)
108
108
  @send_pump = @engine.spawn_conn_pump_task(conn, annotation: "send pump") do
109
+ batch = []
110
+
109
111
  loop do
110
- batch = [@send_queue.dequeue]
111
- Routing.drain_send_queue(@send_queue, batch)
112
+ Routing.dequeue_batch(@send_queue, batch)
112
113
 
113
114
  if batch.size == 1
114
115
  conn.write_message(batch.first)
@@ -120,6 +121,7 @@ module OMQ
120
121
  batch.each do |parts|
121
122
  @engine.emit_verbose_msg_sent(conn, parts)
122
123
  end
124
+ batch.clear
123
125
  end
124
126
  end
125
127
 
@@ -55,7 +55,7 @@ module OMQ
55
55
  envelope = msg[0, delimiter]
56
56
  body = msg[(delimiter + 1)..] || []
57
57
 
58
- @pending_replies << { conn: connection, envelope: envelope }
58
+ @pending_replies << [connection, envelope]
59
59
  body
60
60
  end
61
61
  @tasks << task if task
@@ -69,7 +69,7 @@ module OMQ
69
69
  # @param connection [Connection]
70
70
  #
71
71
  def connection_removed(connection)
72
- @pending_replies.reject! { |r| r[:conn] == connection }
72
+ @pending_replies.reject! { |r| r[0] == connection }
73
73
  @conn_queues.delete(connection)
74
74
  @conn_send_tasks.delete(connection)&.stop
75
75
  end
@@ -83,8 +83,12 @@ module OMQ
83
83
  def enqueue(parts)
84
84
  reply_info = @pending_replies.shift
85
85
  return unless reply_info
86
- conn = reply_info[:conn]
87
- @conn_queues[conn]&.enqueue([*reply_info[:envelope], EMPTY_FRAME, *parts])
86
+
87
+ conn, envelope = reply_info
88
+ msg = envelope
89
+ msg << EMPTY_FRAME
90
+ msg.concat(parts)
91
+ @conn_queues[conn]&.enqueue(msg)
88
92
  end
89
93
 
90
94
 
@@ -93,7 +93,7 @@ module OMQ
93
93
  # REQ prepends empty delimiter frame on the wire.
94
94
  #
95
95
  def transform_send(parts)
96
- [EMPTY_BINARY, *parts]
96
+ parts.dup.unshift(EMPTY_BINARY)
97
97
  end
98
98
 
99
99
  end
@@ -133,9 +133,10 @@ module OMQ
133
133
  #
134
134
  def start_conn_send_pump(conn)
135
135
  task = @engine.spawn_conn_pump_task(conn, annotation: "send pump") do
136
+ batch = []
137
+
136
138
  loop do
137
- batch = [@send_queue.dequeue]
138
- drain_send_queue_capped(batch)
139
+ dequeue_batch_capped(batch)
139
140
  @in_flight += batch.size
140
141
 
141
142
  begin
@@ -147,6 +148,7 @@ module OMQ
147
148
  batch.each do |parts|
148
149
  @engine.emit_verbose_msg_sent(conn, parts)
149
150
  end
151
+ batch.clear
150
152
 
151
153
  Async::Task.current.yield
152
154
  end
@@ -157,7 +159,8 @@ module OMQ
157
159
  end
158
160
 
159
161
 
160
- def drain_send_queue_capped(batch)
162
+ def dequeue_batch_capped(batch = [])
163
+ batch << @send_queue.dequeue
161
164
  bytes = batch_bytes(batch.first)
162
165
 
163
166
  while batch.size < BATCH_MSG_CAP && bytes < BATCH_BYTE_CAP
data/lib/omq/routing.rb CHANGED
@@ -57,7 +57,8 @@ module OMQ
57
57
 
58
58
 
59
59
  # Drains all available messages from +queue+ into +batch+ without
60
- # blocking. Call after the initial blocking dequeue.
60
+ # Blocks for the first message, then sweeps all immediately
61
+ # available messages into +batch+ without blocking.
61
62
  #
62
63
  # No cap is needed: IO::Stream auto-flushes at 64 KB, so the
63
64
  # write buffer hits the wire naturally under sustained load.
@@ -67,7 +68,9 @@ module OMQ
67
68
  # @param batch [Array]
68
69
  # @return [void]
69
70
  #
70
- def self.drain_send_queue(queue, batch)
71
+ def self.dequeue_batch(queue, batch = [])
72
+ batch << queue.dequeue
73
+
71
74
  loop do
72
75
  msg = queue.dequeue(timeout: 0) or break
73
76
  batch << msg
data/lib/omq/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OMQ
4
- VERSION = "0.22.0"
4
+ VERSION = "0.22.1"
5
5
  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.22.0
4
+ version: 0.22.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Patrik Wenger