omq 0.17.2 → 0.17.4

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: f8a35ab8a212a111e78889494ac1eb18f780b6315eb3993eb83d04ae7ebdb222
4
- data.tar.gz: 32727fe82814e3d36843dcbd82d66ecfbd9c26e5c36e7a173bdcf164dd649f75
3
+ metadata.gz: 6c00d04d926fae9c6feb6526a611ff3f2ebc05812c7387ac0f97206c7a0b15bb
4
+ data.tar.gz: 6af6b6ce8996c5f5082aac1f3b44339de359876aa17e01cfe2255b4681a053c6
5
5
  SHA512:
6
- metadata.gz: 1f78b8ff8a907b606ec376a7186a09b77b91317c91f3bdb1ff7ebd600d36d6e6fea4738b72dc4ddd3c611225df4a9c27fbd8418fe73dfcdf7a20985fdee5516b
7
- data.tar.gz: 3811837748c18669dd6dc604c8253cfdb7b0e26a6c9eda3b61a4c711ac441f88b58c283701e6985880aa03d963338b53cc4271c3e456e6499498f9ce21037d85
6
+ metadata.gz: 0db98892b62b35fc06e7a9fca89868ff1dec3bddc5ab4b5d4039bf29290702ed6db122c609c2311789159520638f9339744fdf20df39086b350f183c502075a9
7
+ data.tar.gz: 85eae7b6058ead5d02cdddd41bec7dced3882b44267f1a566bc5964eab11eca6d56de23898f9912f985f86685f32690b2edfc555eee0784ac8f74da470c2cd71
data/CHANGELOG.md CHANGED
@@ -1,5 +1,36 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.17.4 — 2026-04-10
4
+
5
+ ### Fixed
6
+
7
+ - **Connect timeout at the transport level.** `TCP.connect` now uses
8
+ `::Socket.tcp(host, port, connect_timeout:)` instead of
9
+ `TCPSocket.new`. The timeout is derived from the reconnect interval
10
+ (floor 0.5s). Fixes a hang on macOS where a non-blocking IPv6
11
+ `connect(2)` to `::1` via kqueue never delivers `ECONNREFUSED` when
12
+ nothing is listening — `TCPSocket.new` blocked the fiber indefinitely
13
+ because `Async::Task#with_timeout` cannot interrupt C-level blocking
14
+ calls. `::Socket.tcp` uses kernel-level `connect_timeout:` which works
15
+ regardless of the scheduler.
16
+
17
+ ## 0.17.3 — 2026-04-10
18
+
19
+ ### Fixed
20
+
21
+ - **Connect timeout in reconnect loop.** Each connect attempt is now
22
+ capped at the reconnect interval (floor 0.5s) via
23
+ `Async::Task#with_timeout`. Fixes a hang on macOS where a non-blocking
24
+ IPv6 `connect(2)` to `::1` via kqueue never delivers `ECONNREFUSED`
25
+ when nothing is listening — the fiber would block indefinitely,
26
+ stalling the entire reconnect loop.
27
+
28
+ ### Changed
29
+
30
+ - **Extracted `Reconnect#retry_loop`.** The reconnect retry loop is now
31
+ a separate private method, keeping `#run` focused on task spawning and
32
+ error handling.
33
+
3
34
  ## 0.17.2 — 2026-04-10
4
35
 
5
36
  ### Fixed
@@ -37,21 +37,8 @@ module OMQ
37
37
  # @return [void]
38
38
  #
39
39
  def run(parent_task, delay: nil)
40
- delay, max_delay = init_delay(delay)
41
-
42
40
  @engine.tasks << parent_task.async(transient: true, annotation: "reconnect #{@endpoint}") do
43
- loop do
44
- break if @engine.closed?
45
- sleep quantized_wait(delay) if delay > 0
46
- break if @engine.closed?
47
- begin
48
- @engine.transport_for(@endpoint).connect(@endpoint, @engine)
49
- break
50
- rescue *CONNECTION_LOST, *CONNECTION_FAILED, Protocol::ZMTP::Error
51
- delay = next_delay(delay, max_delay)
52
- @engine.emit_monitor_event(:connect_retried, endpoint: @endpoint, detail: { interval: delay })
53
- end
54
- end
41
+ retry_loop(delay: delay)
55
42
  rescue Async::Stop
56
43
  rescue => error
57
44
  @engine.signal_fatal_error(error)
@@ -60,6 +47,25 @@ module OMQ
60
47
 
61
48
  private
62
49
 
50
+
51
+ def retry_loop(delay: nil)
52
+ delay, max_delay = init_delay(delay)
53
+
54
+ loop do
55
+ break if @engine.closed?
56
+ sleep quantized_wait(delay) if delay > 0
57
+ break if @engine.closed?
58
+ begin
59
+ @engine.transport_for(@endpoint).connect(@endpoint, @engine)
60
+ break
61
+ rescue *CONNECTION_LOST, *CONNECTION_FAILED, Protocol::ZMTP::Error
62
+ delay = next_delay(delay, max_delay)
63
+ @engine.emit_monitor_event(:connect_retried, endpoint: @endpoint, detail: { interval: delay })
64
+ end
65
+ end
66
+ end
67
+
68
+
63
69
  # Wall-clock quantized sleep: wait until the next +delay+-sized
64
70
  # grid tick. Multiple clients reconnecting with the same interval
65
71
  # wake up at the same instant, collapsing staggered retries into
@@ -57,12 +57,23 @@ module OMQ
57
57
  #
58
58
  def connect(endpoint, engine)
59
59
  host, port = self.parse_endpoint(endpoint)
60
- sock = TCPSocket.new(host, port)
60
+ sock = ::Socket.tcp(host, port, connect_timeout: connect_timeout(engine.options))
61
61
  apply_buffer_sizes(sock, engine.options)
62
62
  engine.handle_connected(IO::Stream::Buffered.wrap(sock), endpoint: endpoint)
63
63
  end
64
64
 
65
65
 
66
+ # Connect timeout: cap each attempt at the reconnect interval so a
67
+ # hung connect(2) (e.g. macOS kqueue + IPv6 ECONNREFUSED not delivered)
68
+ # doesn't block the retry loop. Floor at 0.5s for real-network latency.
69
+ #
70
+ def connect_timeout(options)
71
+ ri = options.reconnect_interval
72
+ ri = ri.end if ri.is_a?(Range)
73
+ [ri, 0.5].max
74
+ end
75
+
76
+
66
77
  # Parses a TCP endpoint URI into host and port.
67
78
  #
68
79
  # @param endpoint [String]
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.17.2"
4
+ VERSION = "0.17.4"
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.17.2
4
+ version: 0.17.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Patrik Wenger