omq-ffi 0.1.2 → 0.1.3
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/lib/omq/ffi/engine.rb +76 -9
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 644d87fb23e1290cbe1a879a705c835e16858479305a2ebf453b996a10e7cf77
|
|
4
|
+
data.tar.gz: bcd37e11f05619293cb8776b229c2317e488647ae6cfb4b7e401b72e6c614c7e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e10cb300fdebdfe538149a55e901f0594c1f13d69a2d58adbde5674bb632e90dcfaa2fa11749364df762a7220f4a92ad8cfa09f186bd2869e4e6167f1f4792c1
|
|
7
|
+
data.tar.gz: b6971619da183b23a3969a6afdaa7ac8a09de80485253b2f1a82cad8d8d81af865d88c227297507f4c945c82bd2596dbc2dd8f85bd8d92338c4a1168b9f4e4f4
|
data/lib/omq/ffi/engine.rb
CHANGED
|
@@ -28,8 +28,14 @@ module OMQ
|
|
|
28
28
|
attr_reader :peer_connected
|
|
29
29
|
# @return [Async::Promise] resolved when all peers have disconnected
|
|
30
30
|
attr_reader :all_peers_gone
|
|
31
|
+
# @return [Async::Task, nil] root of the engine's task tree
|
|
32
|
+
attr_reader :parent_task
|
|
31
33
|
# @param value [Boolean] enables or disables automatic reconnection
|
|
32
34
|
attr_writer :reconnect_enabled
|
|
35
|
+
# @note Monitor events are not yet emitted by the FFI backend; these
|
|
36
|
+
# writers exist so Socket#monitor can attach without raising. Wiring
|
|
37
|
+
# libzmq's zmq_socket_monitor is a TODO.
|
|
38
|
+
attr_writer :monitor_queue, :verbose_monitor
|
|
33
39
|
|
|
34
40
|
# Routing stub that delegates subscribe/unsubscribe/join/leave to
|
|
35
41
|
# libzmq socket options via the I/O thread.
|
|
@@ -168,6 +174,12 @@ module OMQ
|
|
|
168
174
|
|
|
169
175
|
# Closes the socket and shuts down the I/O thread.
|
|
170
176
|
#
|
|
177
|
+
# Honors `options.linger`:
|
|
178
|
+
# nil → wait forever for Ruby-side queue to drain into libzmq
|
|
179
|
+
# and for libzmq's own LINGER to flush to the network
|
|
180
|
+
# 0 → drop anything not yet in libzmq's kernel buffers, close fast
|
|
181
|
+
# N → up to N seconds for drain + N + 1s grace for join
|
|
182
|
+
#
|
|
171
183
|
# @return [void]
|
|
172
184
|
def close
|
|
173
185
|
return if @closed
|
|
@@ -175,7 +187,15 @@ module OMQ
|
|
|
175
187
|
if @io_thread
|
|
176
188
|
@cmd_queue.push([:stop])
|
|
177
189
|
wake_io_thread
|
|
178
|
-
@
|
|
190
|
+
linger = @options.linger
|
|
191
|
+
if linger.nil?
|
|
192
|
+
@io_thread.join
|
|
193
|
+
elsif linger.zero?
|
|
194
|
+
@io_thread.join(0.5) # fast path: zmq_close is non-blocking with LINGER=0
|
|
195
|
+
else
|
|
196
|
+
@io_thread.join(linger + 1.0)
|
|
197
|
+
end
|
|
198
|
+
@io_thread.kill if @io_thread.alive? # hard stop if deadline exceeded
|
|
179
199
|
else
|
|
180
200
|
# IO thread never started — close socket directly
|
|
181
201
|
L.zmq_close(@zmq_socket)
|
|
@@ -308,14 +328,48 @@ module OMQ
|
|
|
308
328
|
rescue
|
|
309
329
|
# Thread exit
|
|
310
330
|
ensure
|
|
311
|
-
#
|
|
312
|
-
#
|
|
313
|
-
|
|
331
|
+
# Drain Ruby-side send queue into libzmq, bounded by linger deadline.
|
|
332
|
+
# Then re-apply current linger to libzmq (user may have changed it
|
|
333
|
+
# after apply_options ran in initialize) and zmq_close uses it to
|
|
334
|
+
# flush libzmq's own queue to TCP.
|
|
335
|
+
drain_sends_with_deadline(zmq_fd_io, shutdown_deadline) rescue nil
|
|
336
|
+
linger_ms = @options.linger.nil? ? -1 : (@options.linger * 1000).to_i
|
|
337
|
+
set_int_option(L::ZMQ_LINGER, linger_ms) rescue nil
|
|
314
338
|
zmq_fd_io&.close rescue nil
|
|
315
339
|
L.zmq_close(@zmq_socket)
|
|
316
340
|
end
|
|
317
341
|
|
|
318
342
|
|
|
343
|
+
# Returns a monotonic deadline for the Ruby-side drain phase, or nil
|
|
344
|
+
# for infinite, or the current clock for "drop immediately".
|
|
345
|
+
#
|
|
346
|
+
def shutdown_deadline
|
|
347
|
+
linger = @options.linger
|
|
348
|
+
return nil if linger.nil?
|
|
349
|
+
now = Async::Clock.now
|
|
350
|
+
return now if linger.zero?
|
|
351
|
+
now + linger
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
# Retries drain_sends with IO.select until either the Ruby-side queue
|
|
356
|
+
# is empty or the deadline is hit. nil deadline = wait forever.
|
|
357
|
+
#
|
|
358
|
+
def drain_sends_with_deadline(zmq_fd_io, deadline)
|
|
359
|
+
loop do
|
|
360
|
+
drain_sends
|
|
361
|
+
break if @pending_send.nil? && @send_queue.empty?
|
|
362
|
+
if deadline
|
|
363
|
+
remaining = deadline - Async::Clock.now
|
|
364
|
+
break if remaining <= 0
|
|
365
|
+
IO.select([zmq_fd_io], nil, nil, [remaining, 0.1].min)
|
|
366
|
+
else
|
|
367
|
+
IO.select([zmq_fd_io], nil, nil, 0.1)
|
|
368
|
+
end
|
|
369
|
+
end
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
|
|
319
373
|
def zmq_has_events?
|
|
320
374
|
@events_buf ||= ::FFI::MemoryPointer.new(:int)
|
|
321
375
|
@events_len ||= ::FFI::MemoryPointer.new(:size_t).tap { |p| p.write(:size_t, ::FFI.type_size(:int)) }
|
|
@@ -344,16 +398,16 @@ module OMQ
|
|
|
344
398
|
return false
|
|
345
399
|
when :bind
|
|
346
400
|
rc = L.zmq_bind(@zmq_socket, args[0])
|
|
347
|
-
result&.push(rc >= 0 ? nil :
|
|
401
|
+
result&.push(rc >= 0 ? nil : syscall_error)
|
|
348
402
|
when :connect
|
|
349
403
|
rc = L.zmq_connect(@zmq_socket, args[0])
|
|
350
|
-
result&.push(rc >= 0 ? nil :
|
|
404
|
+
result&.push(rc >= 0 ? nil : syscall_error)
|
|
351
405
|
when :disconnect
|
|
352
406
|
rc = L.zmq_disconnect(@zmq_socket, args[0])
|
|
353
|
-
result&.push(rc >= 0 ? nil :
|
|
407
|
+
result&.push(rc >= 0 ? nil : syscall_error)
|
|
354
408
|
when :unbind
|
|
355
409
|
rc = L.zmq_unbind(@zmq_socket, args[0])
|
|
356
|
-
result&.push(rc >= 0 ? nil :
|
|
410
|
+
result&.push(rc >= 0 ? nil : syscall_error)
|
|
357
411
|
when :set_identity
|
|
358
412
|
set_bytes_option(L::ZMQ_IDENTITY, args[0])
|
|
359
413
|
result&.push(nil)
|
|
@@ -477,7 +531,9 @@ module OMQ
|
|
|
477
531
|
def apply_options
|
|
478
532
|
set_int_option(L::ZMQ_SNDHWM, @options.send_hwm)
|
|
479
533
|
set_int_option(L::ZMQ_RCVHWM, @options.recv_hwm)
|
|
480
|
-
|
|
534
|
+
# linger: nil = infinite (-1), N seconds → N*1000 ms, 0 = immediate
|
|
535
|
+
linger_ms = @options.linger.nil? ? -1 : (@options.linger * 1000).to_i
|
|
536
|
+
set_int_option(L::ZMQ_LINGER, linger_ms)
|
|
481
537
|
set_int_option(L::ZMQ_CONFLATE, @options.conflate ? 1 : 0)
|
|
482
538
|
|
|
483
539
|
if @options.identity && !@options.identity.empty?
|
|
@@ -531,6 +587,17 @@ module OMQ
|
|
|
531
587
|
end
|
|
532
588
|
|
|
533
589
|
|
|
590
|
+
# Builds an Errno::XXX exception from the current zmq_errno so callers
|
|
591
|
+
# can rescue the same classes they would from the pure-Ruby backend
|
|
592
|
+
# (e.g. `Errno::EADDRINUSE`, `Errno::ECONNREFUSED`). Falls back to a
|
|
593
|
+
# plain SystemCallError when the errno is libzmq-specific.
|
|
594
|
+
#
|
|
595
|
+
def syscall_error
|
|
596
|
+
errno = L.zmq_errno
|
|
597
|
+
SystemCallError.new(L.zmq_strerror(errno), errno)
|
|
598
|
+
end
|
|
599
|
+
|
|
600
|
+
|
|
534
601
|
def extract_tcp_port(endpoint)
|
|
535
602
|
return nil unless endpoint
|
|
536
603
|
port = endpoint.split(":").last.to_i
|