omq 0.15.3 → 0.15.5

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: d1aa0586915986b6147a3433605657386ba586a8457e1ef2e0542b89f15da8d5
4
- data.tar.gz: 7d6507a015ca32b74ee3b449f29982f3d4766975628bfea13966f77d14ec8d2f
3
+ metadata.gz: a3c8e182cc758212708988bb4c88a7d374c63f06053e3be829c3a98620e23450
4
+ data.tar.gz: da1bdea2c47ec1c0a8e5e15d0b4ea69c9af642cd7fc67eae4b0931209314eac3
5
5
  SHA512:
6
- metadata.gz: f1dfb171e7aaa086e08a4f8ea0a30e4f13883e7e1879302edfbb0ca12ecf70176369f7aabe1861efaad5867bd8dd0ea935fd8e37cd52df5974c17391145cc8eb
7
- data.tar.gz: 5c33383958134a31830b4449b7de15b92ab7221597c00537ae2cea8a53bb029bf289022043acede991459a3a64d74b2cc90ed97494e7961d98a7b6b9259fdbe7
6
+ metadata.gz: 6d56451299b8e3cfc500ea145826d8e1bc251edf814dc0e4fea6846428ff546bd3f7f66005e4c41b55d9b4b54c6e536f62619de6086311cdd538a16080e2802e
7
+ data.tar.gz: 1f5b9061e5eae37357c4d6e1dc828bac2778f68ba6a10072faecc4d049b9517e2044b66bc4771b1a16dc38717583e7689cb74b9e653b0df15171e0723bd1150a
data/CHANGELOG.md CHANGED
@@ -1,6 +1,37 @@
1
1
  # Changelog
2
2
 
3
- ## Unreleased
3
+ ## 0.15.5 — 2026-04-08
4
+
5
+ - **`max_message_size` now defaults to `nil` (unlimited)** — previous
6
+ default of 1 MiB moved into omq-cli.
7
+ - **Benchmark suite: calibration-driven measurement.** Each cell auto-sizes
8
+ `n` from a prime burst + doubling warmup, then runs `ROUNDS=3` timed
9
+ rounds of `ROUND_DURATION=1.0 s` (override via `OMQ_BENCH_TARGET`) and
10
+ reports the fastest. Full suite runs in ~3 min.
11
+ - **Benchmark suite: dropped `curve` transport and the `pair` /
12
+ `dealer_dealer` pattern scripts from the default loop.** Files stay in
13
+ place for ad-hoc runs.
14
+ - **`bench/push_pull/omq.rb`** now runs `peer_counts: [1, 3]`.
15
+ - **`bench/report.rb --update-readme`** regenerates the PUSH/PULL and
16
+ REQ/REP tables in `bench/README.md` from the latest run in
17
+ `results.jsonl`, between `<!-- BEGIN … -->` / `<!-- END … -->` markers.
18
+
19
+ ## 0.15.4 — 2026-04-08
20
+
21
+ - **Lazy routing initialization** — the routing strategy is now created on
22
+ first use (bind, connect, send, or receive) instead of eagerly in the
23
+ constructor. This allows socket option setters (`send_hwm=`, `recv_hwm=`)
24
+ to take effect before internal queue sizing.
25
+ - **Prefetch byte limit** — `dequeue_recv_batch` now stops at 1 MB total,
26
+ not just 64 messages. Prevents large messages from filling the prefetch
27
+ buffer with hundreds of megabytes.
28
+ - **Bound staging queue `@head`** — `StagingQueue#prepend` now drops messages
29
+ when at capacity, preventing unbounded growth during reconnect cycles.
30
+ - **Bound monitor queue** — `Socket#monitor` uses a `LimitedQueue(64)` instead
31
+ of an unbounded queue, preventing memory growth when verbose monitoring
32
+ can't keep up with message rate.
33
+
34
+ ## 0.15.3 — 2026-04-08
4
35
 
5
36
  - **Auto-freeze on bind/connect** — `#bind` and `#connect` now call
6
37
  `OMQ.freeze_for_ractors!` automatically, freezing `CONNECTION_LOST`,
data/README.md CHANGED
@@ -147,7 +147,7 @@ end
147
147
 
148
148
  ## Socket Types
149
149
 
150
- All sockets are thread-safe. Default HWM is 1000 messages per socket. Default `max_message_size` is **1 MiB** — frames larger than this cause the connection to be dropped before the body is read from the wire. Set `socket.max_message_size = nil` to disable the limit or raise it as needed. Classes live under `OMQ::` (alias: `ØMQ`).
150
+ All sockets are thread-safe. Default HWM is 1000 messages per socket. `max_message_size` defaults to **`nil` (unlimited)** — set `socket.max_message_size = N` to cap inbound frames at `N` bytes; oversized frames cause the connection to be dropped before the body is read from the wire. Classes live under `OMQ::` (alias: `ØMQ`).
151
151
 
152
152
  #### Standard (multipart messages)
153
153
 
data/lib/omq/engine.rb CHANGED
@@ -42,9 +42,11 @@ module OMQ
42
42
  attr_reader :options
43
43
 
44
44
 
45
- # @return [Routing] routing strategy
45
+ # @return [Routing] routing strategy (created lazily on first access)
46
46
  #
47
- attr_reader :routing
47
+ def routing
48
+ @routing ||= Routing.for(@socket_type).new(self)
49
+ end
48
50
 
49
51
 
50
52
  # @return [String, nil] last bound endpoint
@@ -63,7 +65,7 @@ module OMQ
63
65
  def initialize(socket_type, options)
64
66
  @socket_type = socket_type
65
67
  @options = options
66
- @routing = Routing.for(socket_type).new(self)
68
+ @routing = nil
67
69
  @connections = {} # connection => ConnectionRecord
68
70
  @dialed = Set.new # endpoints we called connect() on (reconnect intent)
69
71
  @listeners = []
@@ -225,7 +227,7 @@ module OMQ
225
227
  pipe = @connection_wrapper.call(pipe) if @connection_wrapper
226
228
  @connections[pipe] = ConnectionRecord.new(endpoint: endpoint, done: nil)
227
229
  emit_monitor_event(:handshake_succeeded, endpoint: endpoint)
228
- @routing.connection_added(pipe)
230
+ routing.connection_added(pipe)
229
231
  @peer_connected.resolve(pipe)
230
232
  end
231
233
 
@@ -237,28 +239,31 @@ module OMQ
237
239
  #
238
240
  def dequeue_recv
239
241
  raise @fatal_error if @fatal_error
240
- msg = @routing.recv_queue.dequeue
242
+ msg = routing.recv_queue.dequeue
241
243
  raise @fatal_error if msg.nil? && @fatal_error
242
244
  msg
243
245
  end
244
246
 
245
247
 
246
- # Dequeues up to +max+ messages. Blocks on the first, then
247
- # drains non-blocking.
248
+ # Dequeues up to +max+ messages or +max_bytes+ total. Blocks
249
+ # on the first, then drains non-blocking.
248
250
  #
249
- # @param max [Integer]
251
+ # @param max [Integer] message count limit
252
+ # @param max_bytes [Integer] byte size limit
250
253
  # @return [Array<Array<String>>]
251
254
  #
252
- def dequeue_recv_batch(max)
255
+ def dequeue_recv_batch(max, max_bytes: 1 << 20)
253
256
  raise @fatal_error if @fatal_error
254
- queue = @routing.recv_queue
257
+ queue = routing.recv_queue
255
258
  msg = queue.dequeue
256
259
  raise @fatal_error if msg.nil? && @fatal_error
257
260
  batch = [msg]
258
- while batch.size < max
261
+ bytes = msg.sum(&:bytesize)
262
+ while batch.size < max && bytes < max_bytes
259
263
  msg = queue.dequeue(timeout: 0)
260
264
  break unless msg
261
265
  batch << msg
266
+ bytes += msg.sum(&:bytesize)
262
267
  end
263
268
  batch
264
269
  end
@@ -268,7 +273,7 @@ module OMQ
268
273
  # pending {#dequeue_recv} with a nil return value.
269
274
  #
270
275
  def dequeue_recv_sentinel
271
- @routing.recv_queue.push(nil)
276
+ routing.recv_queue.push(nil)
272
277
  end
273
278
 
274
279
 
@@ -280,7 +285,7 @@ module OMQ
280
285
  #
281
286
  def enqueue_send(parts)
282
287
  raise @fatal_error if @fatal_error
283
- @routing.enqueue(parts)
288
+ routing.enqueue(parts)
284
289
  end
285
290
 
286
291
 
@@ -305,7 +310,7 @@ module OMQ
305
310
  #
306
311
  def connection_lost(connection)
307
312
  entry = @connections.delete(connection)
308
- @routing.connection_removed(connection)
313
+ routing.connection_removed(connection)
309
314
  connection.close
310
315
  emit_monitor_event(:disconnected, endpoint: entry&.endpoint)
311
316
  entry&.done&.resolve(true)
@@ -369,7 +374,7 @@ module OMQ
369
374
  rescue => wrapped
370
375
  wrapped
371
376
  end
372
- @routing.recv_queue.push(nil) rescue nil
377
+ routing.recv_queue.push(nil) rescue nil
373
378
  @peer_connected.resolve(nil) rescue nil
374
379
  end
375
380
 
@@ -502,14 +507,14 @@ module OMQ
502
507
  conns = @connections.filter_map { |conn, e| conn if e.endpoint == endpoint }
503
508
  conns.each do |conn|
504
509
  @connections.delete(conn)
505
- @routing.connection_removed(conn)
510
+ routing.connection_removed(conn)
506
511
  conn.close
507
512
  end
508
513
  end
509
514
 
510
515
 
511
516
  def stop_tasks
512
- @routing.stop rescue nil
517
+ routing.stop rescue nil
513
518
  @tasks.each { |t| t.stop rescue nil }
514
519
  @tasks.clear
515
520
  end
data/lib/omq/options.rb CHANGED
@@ -24,7 +24,7 @@ module OMQ
24
24
  @heartbeat_interval = nil # seconds, nil = disabled
25
25
  @heartbeat_ttl = nil # seconds, nil = use heartbeat_interval
26
26
  @heartbeat_timeout = nil # seconds, nil = use heartbeat_interval
27
- @max_message_size = 1 << 20 # bytes (1 MiB default)
27
+ @max_message_size = nil # bytes, nil = unlimited
28
28
  @conflate = false
29
29
  @sndbuf = nil # bytes, nil = OS default
30
30
  @rcvbuf = nil # bytes, nil = OS default
@@ -12,7 +12,8 @@ module OMQ
12
12
  # @param max [Integer, nil] capacity (nil or 0 = unbounded)
13
13
  #
14
14
  def initialize(max = nil)
15
- @queue = (max && max > 0) ? Async::LimitedQueue.new(max) : Async::Queue.new
15
+ @max = (max && max > 0) ? max : nil
16
+ @queue = @max ? Async::LimitedQueue.new(@max) : Async::Queue.new
16
17
  @head = []
17
18
  @mu = Mutex.new
18
19
  end
@@ -30,13 +31,18 @@ module OMQ
30
31
 
31
32
 
32
33
  # Inserts a message at the front (for re-staging after a
33
- # failed drain).
34
+ # failed drain). Drops the message if the staging queue is
35
+ # already at capacity (messages sent to a peer that disconnected
36
+ # may be lost -- same as ZMQ).
34
37
  #
35
38
  # @param msg [Array<String>]
36
39
  # @return [void]
37
40
  #
38
41
  def prepend(msg)
39
- @mu.synchronize { @head.push(msg) }
42
+ @mu.synchronize do
43
+ return if @max && @head.size >= @max
44
+ @head.push(msg)
45
+ end
40
46
  end
41
47
 
42
48
 
data/lib/omq/socket.rb CHANGED
@@ -174,7 +174,7 @@ module OMQ
174
174
  #
175
175
  def monitor(verbose: false, &block)
176
176
  ensure_parent_task
177
- queue = Async::Queue.new
177
+ queue = Async::LimitedQueue.new(64)
178
178
  @engine.monitor_queue = queue
179
179
  @engine.verbose_monitor = verbose
180
180
  Reactor.run do
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.15.3"
4
+ VERSION = "0.15.5"
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.15.3
4
+ version: 0.15.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Patrik Wenger