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.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +162 -0
  3. data/README.md +17 -21
  4. data/lib/omq/channel.rb +35 -0
  5. data/lib/omq/client_server.rb +72 -0
  6. data/lib/omq/constants.rb +68 -0
  7. data/lib/omq/engine/connection_lifecycle.rb +22 -8
  8. data/lib/omq/engine/heartbeat.rb +3 -4
  9. data/lib/omq/engine/maintenance.rb +4 -5
  10. data/lib/omq/engine/reconnect.rb +12 -11
  11. data/lib/omq/engine/recv_pump.rb +10 -10
  12. data/lib/omq/engine/socket_lifecycle.rb +26 -9
  13. data/lib/omq/engine.rb +202 -90
  14. data/lib/omq/peer.rb +49 -0
  15. data/lib/omq/pub_sub.rb +2 -2
  16. data/lib/omq/radio_dish.rb +122 -0
  17. data/lib/omq/reactor.rb +14 -5
  18. data/lib/omq/readable.rb +5 -1
  19. data/lib/omq/routing/channel.rb +110 -0
  20. data/lib/omq/routing/client.rb +70 -0
  21. data/lib/omq/routing/conn_send_pump.rb +5 -8
  22. data/lib/omq/routing/dealer.rb +3 -15
  23. data/lib/omq/routing/dish.rb +94 -0
  24. data/lib/omq/routing/fan_out.rb +12 -16
  25. data/lib/omq/routing/gather.rb +60 -0
  26. data/lib/omq/routing/pair.rb +7 -26
  27. data/lib/omq/routing/peer.rb +95 -0
  28. data/lib/omq/routing/pub.rb +2 -13
  29. data/lib/omq/routing/pull.rb +3 -15
  30. data/lib/omq/routing/push.rb +4 -13
  31. data/lib/omq/routing/radio.rb +187 -0
  32. data/lib/omq/routing/rep.rb +5 -19
  33. data/lib/omq/routing/req.rb +6 -18
  34. data/lib/omq/routing/round_robin.rb +15 -19
  35. data/lib/omq/routing/router.rb +5 -19
  36. data/lib/omq/routing/scatter.rb +76 -0
  37. data/lib/omq/routing/server.rb +90 -0
  38. data/lib/omq/routing/sub.rb +3 -15
  39. data/lib/omq/routing/xpub.rb +2 -13
  40. data/lib/omq/routing/xsub.rb +8 -25
  41. data/lib/omq/scatter_gather.rb +56 -0
  42. data/lib/omq/socket.rb +8 -23
  43. data/lib/omq/transport/inproc/{direct_pipe.rb → pipe.rb} +26 -24
  44. data/lib/omq/transport/inproc.rb +22 -14
  45. data/lib/omq/transport/ipc.rb +41 -13
  46. data/lib/omq/transport/tcp.rb +59 -23
  47. data/lib/omq/transport/udp.rb +281 -0
  48. data/lib/omq/version.rb +1 -1
  49. data/lib/omq/writable.rb +11 -42
  50. data/lib/omq.rb +9 -64
  51. metadata +17 -3
  52. data/lib/omq/monitor_event.rb +0 -16
@@ -4,7 +4,7 @@ module OMQ
4
4
  class Engine
5
5
  # Recv pump for a connection.
6
6
  #
7
- # For inproc DirectPipe: wires the direct recv path (no fiber spawned).
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::DirectPipe]
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::DirectPipe]
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 DirectPipe, wires the direct path
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,9 +60,8 @@ module OMQ
60
60
  # @return [Async::Task, nil]
61
61
  #
62
62
  def start(parent_task, transform)
63
- if @conn.is_a?(Transport::Inproc::DirectPipe) && @conn.peer
64
- @conn.peer.direct_recv_queue = @recv_queue
65
- @conn.peer.direct_recv_transform = transform
63
+ if @conn.is_a?(Transport::Inproc::Pipe) && @conn.peer
64
+ @conn.peer.wire_direct_recv(@recv_queue, transform)
66
65
  return nil
67
66
  end
68
67
 
@@ -73,6 +72,7 @@ module OMQ
73
72
  end
74
73
  end
75
74
 
75
+
76
76
  private
77
77
 
78
78
 
@@ -94,7 +94,7 @@ module OMQ
94
94
 
95
95
  while count < FAIRNESS_MESSAGES && bytes < FAIRNESS_BYTES
96
96
  msg = conn.receive_message
97
- msg = transform.call(msg).freeze
97
+ msg = transform.call(msg)
98
98
 
99
99
  # Emit the verbose trace BEFORE enqueueing so the monitor
100
100
  # fiber is woken before the application fiber -- the
@@ -125,7 +125,7 @@ module OMQ
125
125
  rescue Protocol::ZMTP::Error, *CONNECTION_LOST => error
126
126
  # expected disconnect — stash reason for the :disconnected
127
127
  # monitor event, let the lifecycle reconnect as usual
128
- engine.connections[conn]&.record_disconnect_reason(error)
128
+ engine.record_disconnect_reason(conn, error)
129
129
  rescue => error
130
130
  engine.signal_fatal_error(error)
131
131
  end
@@ -172,7 +172,7 @@ module OMQ
172
172
  rescue Protocol::ZMTP::Error, *CONNECTION_LOST => error
173
173
  # expected disconnect — stash reason for the :disconnected
174
174
  # monitor event, let the lifecycle reconnect as usual
175
- engine.connections[conn]&.record_disconnect_reason(error)
175
+ engine.record_disconnect_reason(conn, error)
176
176
  rescue => error
177
177
  engine.signal_fatal_error(error)
178
178
  end
@@ -28,11 +28,11 @@ module OMQ
28
28
 
29
29
 
30
30
  TRANSITIONS = {
31
- new: %i[open closed].freeze,
32
- open: %i[closing closed].freeze,
33
- closing: %i[closed].freeze,
34
- closed: [].freeze,
35
- }.freeze
31
+ new: %i[open closed],
32
+ open: %i[closing closed],
33
+ closing: %i[closed],
34
+ closed: [],
35
+ }.transform_values(&:freeze).freeze
36
36
 
37
37
 
38
38
  # @return [Symbol]
@@ -74,8 +74,8 @@ module OMQ
74
74
  @peer_connected = Async::Promise.new
75
75
  @all_peers_gone = Async::Promise.new
76
76
  @reconnect_enabled = true
77
- @parent_task = nil
78
77
  @on_io_thread = false
78
+ @parent_task = nil
79
79
  @barrier = nil
80
80
  end
81
81
 
@@ -106,6 +106,7 @@ module OMQ
106
106
  #
107
107
  def capture_parent_task(parent: nil, linger:)
108
108
  return false if @parent_task
109
+
109
110
  if parent
110
111
  @parent_task = parent
111
112
  elsif Async::Task.current?
@@ -115,6 +116,7 @@ module OMQ
115
116
  @on_io_thread = true
116
117
  Reactor.track_linger(linger)
117
118
  end
119
+
118
120
  @barrier = Async::Barrier.new(parent: @parent_task)
119
121
  transition!(:open)
120
122
  true
@@ -134,10 +136,23 @@ module OMQ
134
136
  end
135
137
 
136
138
 
137
- # Resolves `all_peers_gone` if we had peers and now have none.
139
+ # Hard close from any alive state used by {Engine#stop}'s crash
140
+ # path, which skips the linger drain. Goes `:open → :closed`
141
+ # directly when needed.
142
+ def force_close!
143
+ transition!(:closed)
144
+ end
145
+
146
+
147
+ # Resolves `all_peers_gone` once we had peers and the connection map
148
+ # is empty. Called by {Engine#maybe_resolve_all_peers_gone} after a
149
+ # teardown removes a peer.
150
+ #
138
151
  # @param connections [Hash] current connection map
139
- def resolve_all_peers_gone_if_empty(connections)
140
- return unless @peer_connected.resolved? && connections.empty?
152
+ def maybe_resolve_all_peers_gone(connections)
153
+ return unless @peer_connected.resolved?
154
+ return unless connections.empty?
155
+
141
156
  @all_peers_gone.resolve(true)
142
157
  end
143
158
 
@@ -147,9 +162,11 @@ module OMQ
147
162
 
148
163
  def transition!(new_state)
149
164
  allowed = TRANSITIONS[@state]
165
+
150
166
  unless allowed&.include?(new_state)
151
167
  raise InvalidTransition, "#{@state} → #{new_state}"
152
168
  end
169
+
153
170
  @state = new_state
154
171
  end
155
172