omq-cli 0.7.1 → 0.8.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.
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OMQ
4
+ module CLI
5
+ # Shared Ractor infrastructure for parallel worker modes.
6
+ module RactorHelpers
7
+ # Sentinel value sent through ports to signal consumer threads to exit.
8
+ # Port#close does not unblock a waiting #receive, so we must send an
9
+ # explicit shutdown marker.
10
+ SHUTDOWN = :__omq_shutdown__
11
+
12
+
13
+ # Resolves TCP hostnames to IP addresses so Ractors don't touch
14
+ # Resolv::DefaultResolver (which is not shareable).
15
+ #
16
+ def self.preresolve_tcp(endpoints)
17
+ endpoints.flat_map do |ep|
18
+ url = ep.url
19
+ if url.start_with?("tcp://")
20
+ host, port = OMQ::Transport::TCP.parse_endpoint(url)
21
+ Addrinfo.getaddrinfo(host, port, nil, :STREAM).map do |addr|
22
+ ip = addr.ip_address
23
+ ip = "[#{ip}]" if ip.include?(":")
24
+ Endpoint.new("tcp://#{ip}:#{addr.ip_port}", ep.bind?)
25
+ end
26
+ else
27
+ ep
28
+ end
29
+ end
30
+ end
31
+
32
+
33
+ # Starts a Ractor::Port and a consumer thread that drains log
34
+ # messages to stderr sequentially. Returns [port, thread].
35
+ # Send SHUTDOWN through the port to stop the consumer.
36
+ #
37
+ def self.start_log_consumer
38
+ port = Ractor::Port.new
39
+ thread = Thread.new(port) do |p|
40
+ loop do
41
+ msg = p.receive
42
+ break if msg.equal?(SHUTDOWN)
43
+ $stderr.write("#{msg}\n")
44
+ rescue Ractor::ClosedError
45
+ break
46
+ end
47
+ end
48
+ [port, thread]
49
+ end
50
+
51
+
52
+ # Starts a Ractor::Port and a consumer thread that drains
53
+ # formatted output to stdout sequentially. Returns [port, thread].
54
+ # Send SHUTDOWN through the port to stop the consumer.
55
+ #
56
+ def self.start_output_consumer
57
+ port = Ractor::Port.new
58
+ thread = Thread.new(port) do |p|
59
+ loop do
60
+ msg = p.receive
61
+ break if msg.equal?(SHUTDOWN)
62
+ $stdout.write(msg)
63
+ rescue Ractor::ClosedError
64
+ break
65
+ end
66
+ end
67
+ [port, thread]
68
+ end
69
+
70
+
71
+ # Sends the shutdown sentinel and joins the consumer thread.
72
+ #
73
+ def self.stop_consumer(port, thread)
74
+ port.send(SHUTDOWN)
75
+ thread.join
76
+ rescue Ractor::ClosedError
77
+ thread.join(1)
78
+ end
79
+ end
80
+ end
81
+ end
@@ -37,6 +37,11 @@ module OMQ
37
37
 
38
38
  # Runner for REP sockets (synchronous request-reply server).
39
39
  class RepRunner < BaseRunner
40
+ def call(task)
41
+ config.parallel ? run_parallel_workers(:REP) : super
42
+ end
43
+
44
+
40
45
  private
41
46
 
42
47
 
@@ -10,6 +10,14 @@ module OMQ
10
10
 
11
11
  # Runner for GATHER sockets (draft; fan-in receive).
12
12
  class GatherRunner < BaseRunner
13
+ def call(task)
14
+ config.parallel ? run_parallel_workers(:GATHER) : super
15
+ end
16
+
17
+
18
+ private
19
+
20
+
13
21
  def run_loop(task) = run_recv_logic
14
22
  end
15
23
  end
@@ -6,23 +6,30 @@ module OMQ
6
6
  # All methods are module-level so callers compose rather than inherit.
7
7
  #
8
8
  module SocketSetup
9
+ # Apply common socket options from +config+ to +sock+.
10
+ #
11
+ def self.apply_options(sock, config)
12
+ sock.linger = config.linger
13
+ sock.recv_timeout = config.timeout if config.timeout
14
+ sock.send_timeout = config.timeout if config.timeout
15
+ sock.reconnect_interval = config.reconnect_ivl if config.reconnect_ivl
16
+ sock.heartbeat_interval = config.heartbeat_ivl if config.heartbeat_ivl
17
+ sock.send_hwm = config.send_hwm if config.send_hwm
18
+ sock.recv_hwm = config.recv_hwm if config.recv_hwm
19
+ sock.sndbuf = config.sndbuf if config.sndbuf
20
+ sock.rcvbuf = config.rcvbuf if config.rcvbuf
21
+ end
22
+
23
+
9
24
  # Create and fully configure a socket from +klass+ and +config+.
10
25
  #
11
26
  def self.build(klass, config)
12
- sock_opts = { linger: config.linger }
13
- sock_opts[:conflate] = true if config.conflate && %w[pub radio].include?(config.type_name)
14
- sock = klass.new(**sock_opts)
15
- sock.recv_timeout = config.timeout if config.timeout
16
- sock.send_timeout = config.timeout if config.timeout
17
- sock.max_message_size = config.recv_maxsz if config.recv_maxsz
18
- sock.send_hwm = config.send_hwm if config.send_hwm
19
- sock.recv_hwm = config.recv_hwm if config.recv_hwm
20
- sock.sndbuf = config.sndbuf if config.sndbuf
21
- sock.rcvbuf = config.rcvbuf if config.rcvbuf
22
- sock.reconnect_interval = config.reconnect_ivl if config.reconnect_ivl
23
- sock.heartbeat_interval = config.heartbeat_ivl if config.heartbeat_ivl
24
- sock.identity = config.identity if config.identity
25
- sock.router_mandatory = true if config.type_name == "router"
27
+ sock = klass.new
28
+ sock.conflate = true if config.conflate && %w[pub radio].include?(config.type_name)
29
+ apply_options(sock, config)
30
+ sock.max_message_size = config.recv_maxsz if config.recv_maxsz
31
+ sock.identity = config.identity if config.identity
32
+ sock.router_mandatory = true if config.type_name == "router"
26
33
  sock
27
34
  end
28
35
 
@@ -31,7 +31,7 @@ module OMQ
31
31
 
32
32
 
33
33
  # Signal that the first message has been sent or received.
34
- # Idempotent safe to call multiple times.
34
+ # Idempotent -- safe to call multiple times.
35
35
  #
36
36
  def ready!
37
37
  @barrier.resolve(true) unless @barrier.resolved?
@@ -2,6 +2,6 @@
2
2
 
3
3
  module OMQ
4
4
  module CLI
5
- VERSION = "0.7.1"
5
+ VERSION = "0.8.0"
6
6
  end
7
7
  end
data/lib/omq/cli.rb CHANGED
@@ -18,6 +18,9 @@ require_relative "cli/req_rep"
18
18
  require_relative "cli/pair"
19
19
  require_relative "cli/router_dealer"
20
20
  require_relative "cli/client_server"
21
+ require_relative "cli/ractor_helpers"
22
+ require_relative "cli/parallel_worker"
23
+ require_relative "cli/pipe_worker"
21
24
  require_relative "cli/pipe"
22
25
 
23
26
  module OMQ
@@ -168,7 +171,7 @@ module OMQ
168
171
  abort "CURVE requires libsodium. Install it:\n" \
169
172
  " apt install libsodium-dev # Debian/Ubuntu\n" \
170
173
  " brew install libsodium # macOS\n" \
171
- "Or use nuckle (pure Ruby, DANGEROUS not audited):\n" \
174
+ "Or use nuckle (pure Ruby, DANGEROUS -- not audited):\n" \
172
175
  " --crypto nuckle"
173
176
  end
174
177
  else
@@ -220,6 +223,7 @@ module OMQ
220
223
  end
221
224
 
222
225
  if config.type_name.nil?
226
+ Process.setproctitle("omq script")
223
227
  Object.include(OMQ) unless Object.include?(OMQ)
224
228
  Async annotation: 'omq' do
225
229
  Async::Debug.serve(endpoint: debug_ep) if debug_ep
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: omq-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.1
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Patrik Wenger
@@ -165,9 +165,12 @@ files:
165
165
  - lib/omq/cli/expression_evaluator.rb
166
166
  - lib/omq/cli/formatter.rb
167
167
  - lib/omq/cli/pair.rb
168
+ - lib/omq/cli/parallel_worker.rb
168
169
  - lib/omq/cli/pipe.rb
170
+ - lib/omq/cli/pipe_worker.rb
169
171
  - lib/omq/cli/pub_sub.rb
170
172
  - lib/omq/cli/push_pull.rb
173
+ - lib/omq/cli/ractor_helpers.rb
171
174
  - lib/omq/cli/radio_dish.rb
172
175
  - lib/omq/cli/req_rep.rb
173
176
  - lib/omq/cli/router_dealer.rb