cztop 1.3.1 → 2.0.0.rc2
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/CHANGES.md +110 -0
- data/CLAUDE.md +39 -0
- data/Gemfile +0 -4
- data/README.md +92 -177
- data/ZGUIDE_SUMMARY.md +1109 -0
- data/cztop.gemspec +6 -9
- data/lib/cztop/curve/auth.rb +100 -0
- data/lib/cztop/curve.rb +126 -0
- data/lib/cztop/ffi.rb +489 -0
- data/lib/cztop/has_ffi_delegate.rb +20 -9
- data/lib/cztop/monitor.rb +88 -87
- data/lib/cztop/socket/dealer.rb +30 -0
- data/lib/cztop/socket/fd_wait.rb +88 -0
- data/lib/cztop/socket/pair.rb +30 -0
- data/lib/cztop/socket/pub.rb +29 -0
- data/lib/cztop/socket/pull.rb +29 -0
- data/lib/cztop/socket/push.rb +29 -0
- data/lib/cztop/socket/readable.rb +76 -0
- data/lib/cztop/socket/rep.rb +30 -0
- data/lib/cztop/socket/req.rb +30 -0
- data/lib/cztop/socket/router.rb +40 -0
- data/lib/cztop/socket/stream.rb +31 -0
- data/lib/cztop/socket/sub.rb +52 -0
- data/lib/cztop/socket/types.rb +2 -341
- data/lib/cztop/socket/writable.rb +86 -0
- data/lib/cztop/socket/xpub.rb +30 -0
- data/lib/cztop/socket/xsub.rb +30 -0
- data/lib/cztop/socket.rb +68 -27
- data/lib/cztop/version.rb +1 -1
- data/lib/cztop/zsock_options.rb +333 -364
- data/lib/cztop.rb +28 -48
- metadata +34 -63
- data/bin/console +0 -7
- data/bin/setup +0 -7
- data/exe/z85decode +0 -31
- data/exe/z85encode +0 -31
- data/lib/cztop/actor.rb +0 -340
- data/lib/cztop/authenticator.rb +0 -113
- data/lib/cztop/beacon.rb +0 -117
- data/lib/cztop/cert_store.rb +0 -65
- data/lib/cztop/certificate.rb +0 -234
- data/lib/cztop/config/comments.rb +0 -77
- data/lib/cztop/config/serialization.rb +0 -102
- data/lib/cztop/config/traversing.rb +0 -188
- data/lib/cztop/config.rb +0 -135
- data/lib/cztop/frame.rb +0 -193
- data/lib/cztop/message/frames.rb +0 -88
- data/lib/cztop/message.rb +0 -220
- data/lib/cztop/metadata.rb +0 -111
- data/lib/cztop/poller/aggregated.rb +0 -142
- data/lib/cztop/poller/zmq.rb +0 -92
- data/lib/cztop/poller/zpoller.rb +0 -125
- data/lib/cztop/poller.rb +0 -245
- data/lib/cztop/polymorphic_zsock_methods.rb +0 -32
- data/lib/cztop/proxy.rb +0 -164
- data/lib/cztop/send_receive_methods.rb +0 -171
- data/lib/cztop/z85/padded.rb +0 -107
- data/lib/cztop/z85/pipe.rb +0 -200
- data/lib/cztop/z85.rb +0 -90
- data/lib/cztop/zap.rb +0 -259
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3381b5cf1edd7c878bb5c26ccc16bf096a354cfab0724a8da61e7f4ce3146272
|
|
4
|
+
data.tar.gz: c6081e0b22ee66190b3d34eb9d4d6a2d5ecfda537e8cdbfc223cfd23d2b56e9f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8142a5ff3b45d88a3ebfc35b3a002dfb8b9be5937f0c37e1779530229d959b0457a1dfd49c062550b2c46d9389e5c3937272e979e5b703d09f68ed4732925201
|
|
7
|
+
data.tar.gz: 8591012e556649e6397c16a871f8f892a8b111ec06339e3271d03fd5eca187268363258429a949eb1d03c8245907cfbf30ae00662d9168f47e28aea14592094f
|
data/CHANGES.md
CHANGED
|
@@ -1,3 +1,113 @@
|
|
|
1
|
+
2.0.0.rc2
|
|
2
|
+
-----
|
|
3
|
+
|
|
4
|
+
### Breaking changes
|
|
5
|
+
|
|
6
|
+
* **Removed `Socket.new_by_type` factory method** — use type-specific constructors
|
|
7
|
+
instead (e.g. `Socket::REQ.new`, `Socket::PUB.new`)
|
|
8
|
+
* **`linger` now defaults to 0** on all socket constructors — ZMQ's default of
|
|
9
|
+
infinite (-1) caused `#close` to block when unsent messages remained. Pass
|
|
10
|
+
`linger:` to override (e.g. `Socket::REQ.new(endpoint, linger: 1)`)
|
|
11
|
+
|
|
12
|
+
2.0.0.rc1
|
|
13
|
+
-----
|
|
14
|
+
|
|
15
|
+
### Breaking changes
|
|
16
|
+
|
|
17
|
+
* **Removed classes:** Actor, Authenticator, Beacon, Certificate, CertStore, Config,
|
|
18
|
+
Frame, Message, Metadata, Monitor, Poller, Proxy, Z85, ZAP
|
|
19
|
+
* **Removed modules:** SendReceiveMethods, PolymorphicZsockMethods
|
|
20
|
+
* **Removed socket types (draft API dropped):** SERVER, CLIENT, RADIO, DISH,
|
|
21
|
+
GATHER, SCATTER
|
|
22
|
+
* **Removed CURVE/PLAIN/GSSAPI security API:**
|
|
23
|
+
- `Socket#CURVE_server!`, `Socket#CURVE_client!`
|
|
24
|
+
- CURVE option methods (`#CURVE_server?`, `#CURVE_serverkey`,
|
|
25
|
+
`#CURVE_secretkey`, `#CURVE_publickey`, etc.)
|
|
26
|
+
- PLAIN option methods (`#PLAIN_server?`, `#PLAIN_username`,
|
|
27
|
+
`#PLAIN_password`, etc.)
|
|
28
|
+
- `#mechanism`, `#zap_domain`
|
|
29
|
+
* **Send/receive API changed:**
|
|
30
|
+
- `#receive` now returns `Array<String>` (was `CZTop::Message`)
|
|
31
|
+
- `#<<` accepts `String` or `Array<String>` directly (was `Message.coerce`)
|
|
32
|
+
- `#send` is the primary method; `#<<` is an alias (note: `#send` shadows
|
|
33
|
+
`Object#send`; use `__send__` for Ruby dispatch)
|
|
34
|
+
- `SendReceiveMethods` split into `Socket::Readable`, `Socket::Writable`, and
|
|
35
|
+
`Socket::FdWait` mixins; socket types include only what they need
|
|
36
|
+
(e.g. PUB includes only Writable, SUB only Readable)
|
|
37
|
+
* **Time-based options now use seconds** (was milliseconds) — applies to
|
|
38
|
+
`#recv_timeout`, `#send_timeout`, `#linger`, `#heartbeat_ivl`, `#heartbeat_ttl`,
|
|
39
|
+
`#heartbeat_timeout`, `#reconnect_ivl`
|
|
40
|
+
* **Sentinel values changed from -1 to nil:**
|
|
41
|
+
- `#recv_timeout` / `#send_timeout` — returns/accepts `nil` instead
|
|
42
|
+
of `-1` for "no timeout"
|
|
43
|
+
- `#linger` — `nil` instead of `-1` for "wait indefinitely"
|
|
44
|
+
- `#heartbeat_timeout` — `nil` instead of `-1` for "use IVL"
|
|
45
|
+
- `#reconnect_ivl` — `nil` instead of `-1` for "disabled"
|
|
46
|
+
* **`Socket::SUB#initialize` subscription is now a `prefix:` kwarg** — was a
|
|
47
|
+
positional parameter; defaults to `EVERYTHING` (`''`), pass `prefix: nil` to
|
|
48
|
+
skip subscribing
|
|
49
|
+
* **`#set_unbounded` moved from PolymorphicZsockMethods to Socket**
|
|
50
|
+
* **`OptionsAccessor` removed** — all option methods now live directly on
|
|
51
|
+
`Socket` (e.g. `socket.sndhwm` instead of `socket.options.sndhwm`)
|
|
52
|
+
* **`#rcvtimeo` / `#sndtimeo` removed** — use `#recv_timeout` / `#send_timeout`
|
|
53
|
+
(aliased as `#read_timeout` / `#write_timeout`). `nil` = no timeout
|
|
54
|
+
(block forever), `0` = nonblocking, positive = timeout in seconds.
|
|
55
|
+
* **Fuzzy `#[]` / `#[]=` accessors removed**
|
|
56
|
+
* **`czmq-ffi-gen` gem dependency removed** — replaced with handcrafted FFI
|
|
57
|
+
bindings in `lib/cztop/ffi.rb`
|
|
58
|
+
* **Minimum Ruby version raised to 3.3**
|
|
59
|
+
|
|
60
|
+
### New features
|
|
61
|
+
|
|
62
|
+
* **`CZTop::Monitor`** — socket event monitoring via CZMQ's zmonitor actor;
|
|
63
|
+
detects CONNECTED, LISTENING, ACCEPTED, DISCONNECTED, and other ZMQ events.
|
|
64
|
+
Returns `Monitor::Event` value objects (`Data.define(:name, :endpoint, :peer_address)`)
|
|
65
|
+
* **`Cztop` module alias** — `Cztop = CZTop` for conventional Ruby naming;
|
|
66
|
+
both `Cztop::Socket::REQ` and `CZTop::Socket::REQ` work
|
|
67
|
+
* **`.bind` and `.connect` class methods** on all socket types —
|
|
68
|
+
`REP.bind(endpoint)` and `REQ.connect(endpoint)` as shorthand for
|
|
69
|
+
`new(nil).tap { |s| s.bind(endpoint) }`; passes through `curve:`,
|
|
70
|
+
`prefix:` (SUB), and other kwargs
|
|
71
|
+
* **CURVE encryption** with ergonomic `curve:` kwarg on all socket constructors:
|
|
72
|
+
- `CZTop::CURVE.keypair` — generate keypairs (32-byte binary)
|
|
73
|
+
- `CZTop::CURVE.public_key(secret_key)` — derive public from secret
|
|
74
|
+
- `CZTop::CURVE.z85_encode` / `.z85_decode` — Z85 utility for interop
|
|
75
|
+
- `CZTop::CURVE::Auth` — in-memory ZAP handler (no filesystem, no zauth actor)
|
|
76
|
+
- Server: `CZTop::Socket::REP.new(endpoint, curve: { secret_key: sk })`
|
|
77
|
+
- Client: `CZTop::Socket::REQ.new(endpoint, curve: { secret_key: sk, server_key: pk })`
|
|
78
|
+
* **`@`/`>` endpoint prefix convention** supported on all socket constructors
|
|
79
|
+
(e.g. `PAIR.new("@inproc://ep")` to bind, `PAIR.new(">inproc://ep")` to connect)
|
|
80
|
+
* **New socket options:**
|
|
81
|
+
- `#reconnect_ivl_max` — max reconnect backoff interval (exponential backoff)
|
|
82
|
+
- `#max_msg_size` — max inbound message size (DoS protection)
|
|
83
|
+
- `#immediate?` / `#immediate=` — queue only for completed connections
|
|
84
|
+
- `#conflate?` / `#conflate=` — keep only last message (last-value-cache)
|
|
85
|
+
- `#tcp_keepalive` / `#tcp_keepalive_idle` / `#tcp_keepalive_cnt` /
|
|
86
|
+
`#tcp_keepalive_intvl` — TCP keepalive tuning
|
|
87
|
+
|
|
88
|
+
### Other changes
|
|
89
|
+
|
|
90
|
+
* **FFI bindings for zactor, zstr, zsock_wait** — foundational bindings for
|
|
91
|
+
CZMQ actor-based APIs (used by Monitor, extensible for future actors)
|
|
92
|
+
* replace old examples with numbered `examples/zguide/` pattern files
|
|
93
|
+
(01–12: req/rep, pub/sub, pipeline, lazy pirate, heartbeat, LVC, clone,
|
|
94
|
+
majordomo, titanic, binary star, freelance)
|
|
95
|
+
* expand ZGUIDE_SUMMARY.md to ~30 min read with working code excerpts,
|
|
96
|
+
threading/concurrency guidance, and common mistakes section
|
|
97
|
+
* replace RSpec with Minitest
|
|
98
|
+
* replace `perf/` with `bench/` using benchmark-ips
|
|
99
|
+
* add per-socket-type integration test files for all 13 types
|
|
100
|
+
* add socket combination tests (ROUTER+REQ, ROUTER+ROUTER, pipeline, XPUB+multi SUB)
|
|
101
|
+
* add HWM mute state tests (PUSH/PULL blocking, PUB/SUB dropping, ROUTER mandatory)
|
|
102
|
+
* add REQ/REP reconnection tests (TCP restart, stuck-state demonstration)
|
|
103
|
+
* add STREAM ↔ raw TCP integration tests
|
|
104
|
+
* add CURVE throughput benchmark (`bench/threads/curve_throughput.rb`)
|
|
105
|
+
* add Shannon entropy system tests for CURVE (`test/system/`)
|
|
106
|
+
* split socket creation from connect/bind to support pre-connect option setting
|
|
107
|
+
* tune FD_TIMEOUT (500ms → 250ms) and JIFFY (15ms → 1ms) for better responsiveness
|
|
108
|
+
* fix zmq_errno race condition in `#raise_zmq_err`
|
|
109
|
+
* move CZMQ signal handler disabling into `lib/cztop/ffi.rb`
|
|
110
|
+
|
|
1
111
|
1.3.2 (1/3/2025)
|
|
2
112
|
-----
|
|
3
113
|
* add 'benchmark' dependency for specs
|
data/CLAUDE.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# CZTop
|
|
2
|
+
|
|
3
|
+
Ruby FFI binding for CZMQ/ZMQ. Version 2.0.0.pre1. Requires Ruby >= 3.3.
|
|
4
|
+
|
|
5
|
+
## Architecture
|
|
6
|
+
|
|
7
|
+
- `lib/cztop/socket.rb` — Socket base class (connect, bind, etc.)
|
|
8
|
+
- `lib/cztop/socket/fd_wait.rb` — `FdWait` mixin: FD polling infrastructure (`FD_TIMEOUT`, `JIFFY`, `#wait_for_fd_signal`, `#wait_for_socket_state`)
|
|
9
|
+
- `lib/cztop/socket/readable.rb` — `Readable` mixin: `#receive` → `Array<String>`, `#wait_readable`, `#read_timeout`
|
|
10
|
+
- `lib/cztop/socket/writable.rb` — `Writable` mixin: `#send` accepts `String`/`Array<String>`, `#<<`, `#wait_writable`, `#write_timeout`
|
|
11
|
+
- `lib/cztop/socket/types.rb` — `Types` constants + `TypeNames`
|
|
12
|
+
- `lib/cztop/socket/{req,rep,dealer,router,pub,sub,xpub,xsub,push,pull,pair,stream}.rb` — individual socket types
|
|
13
|
+
- `lib/cztop/ffi.rb` — FFI bindings (zsock, zmsg, zframe, zstr) + CZMQ signal handler disabling
|
|
14
|
+
- `bench/` — benchmark-ips scripts (async/threads × throughput/latency)
|
|
15
|
+
|
|
16
|
+
### ZMQ FD polling
|
|
17
|
+
|
|
18
|
+
ZMQ uses a single edge-triggered FD for both read/write signaling. `#wait_for_socket_state`
|
|
19
|
+
checks socket readiness first (fast path via `#readable?`/`#writable?`), then polls the FD.
|
|
20
|
+
|
|
21
|
+
- `FD_TIMEOUT` (250ms) — max time in `IO#wait_readable` per loop iteration; safety net for missed edges
|
|
22
|
+
- `JIFFY` (1ms) — sleep after false wakeup (FD signals but socket not ready)
|
|
23
|
+
- Edge misses are rare (~0.2% of calls in ipc/tcp req/rep), never in inproc throughput
|
|
24
|
+
- `IO#wait_readable` is interruptible by signals — Ctrl-C works immediately
|
|
25
|
+
- `__send__` used instead of `send` to avoid clash with ZMQ `#send` method
|
|
26
|
+
- Socket types include only the mixins they need (e.g. PUB includes only Writable, SUB only Readable)
|
|
27
|
+
|
|
28
|
+
### Tuning rationale
|
|
29
|
+
|
|
30
|
+
- JIFFY 15ms→1ms: each edge miss stalls for full JIFFY duration; 1ms reduces impact 15x
|
|
31
|
+
- FD_TIMEOUT 500ms→250ms: halves worst-case stall; no measurable perf impact since FD signals correctly 99.8% of the time
|
|
32
|
+
- Measured with `bench/jiffy_sweep.rb`, `bench/fd_timeout_sweep.rb`, `bench/edge_miss_count.rb`
|
|
33
|
+
|
|
34
|
+
## Benchmarking
|
|
35
|
+
|
|
36
|
+
- Uses benchmark-ips with `warmup: 1, time: 3`
|
|
37
|
+
- Run benchmarks sequentially to reduce variance
|
|
38
|
+
- For parameter sweeps: test multiple values in a single script with 3 runs each, report median
|
|
39
|
+
- Sister project **rbnng** (`/home/roadster/dev/oss/rbnng`) has identical bench structure for comparison
|
data/Gemfile
CHANGED
data/README.md
CHANGED
|
@@ -1,224 +1,139 @@
|
|
|
1
|
-

|
|
2
|
-

|
|
3
|
-

|
|
4
|
-
[](https://codecov.io/gh/paddor/cztop)
|
|
5
|
-
|
|
6
1
|
# CZTop
|
|
7
2
|
|
|
8
|
-
|
|
9
|
-
[
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
mechanisms (like CURVE).
|
|
13
|
-
|
|
3
|
+
[](https://github.com/paddor/cztop/actions/workflows/ci.yml)
|
|
4
|
+
[](https://rubygems.org/gems/cztop)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
[](https://www.ruby-lang.org)
|
|
14
7
|
|
|
15
|
-
|
|
8
|
+
Ruby FFI binding for [CZMQ](http://czmq.zeromq.org/) / [ZeroMQ](https://zeromq.org/) — high-performance asynchronous messaging for distributed systems.
|
|
16
9
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
```ruby
|
|
20
|
-
#! /usr/bin/env ruby
|
|
10
|
+
> **353k msg/s** inproc throughput | **49 µs** fiber roundtrip latency | nonblock fast path
|
|
21
11
|
|
|
22
|
-
|
|
12
|
+
---
|
|
23
13
|
|
|
24
|
-
|
|
25
|
-
source 'https://rubygems.org'
|
|
26
|
-
gem 'cztop', path: '../../'
|
|
27
|
-
gem 'async'
|
|
28
|
-
end
|
|
14
|
+
## Highlights
|
|
29
15
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
16
|
+
- **All socket types** — req/rep, pub/sub, push/pull, dealer/router, xpub/xsub, pair, stream
|
|
17
|
+
- **Async-first** — first-class [async](https://github.com/socketry/async) fiber support, also works with plain threads
|
|
18
|
+
- **Ruby-idiomatic API** — messages as `Array<String>`, errors as exceptions, timeouts as `IO::TimeoutError`
|
|
33
19
|
|
|
34
|
-
|
|
35
|
-
rep_task = task.async do |t|
|
|
36
|
-
socket = CZTop::Socket::REP.new ENDPOINT
|
|
37
|
-
|
|
38
|
-
loop do
|
|
39
|
-
msg = socket.receive
|
|
40
|
-
puts "<<< #{msg.to_a.inspect}"
|
|
41
|
-
socket << msg.to_a.map(&:upcase)
|
|
42
|
-
end
|
|
43
|
-
ensure
|
|
44
|
-
puts "REP done."
|
|
45
|
-
end
|
|
20
|
+
## Install
|
|
46
21
|
|
|
47
|
-
|
|
48
|
-
socket = CZTop::Socket::REQ.new ENDPOINT
|
|
22
|
+
Install CZMQ on your system:
|
|
49
23
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
puts ">>> #{msg.to_a.inspect}"
|
|
54
|
-
end
|
|
24
|
+
```sh
|
|
25
|
+
# Debian/Ubuntu
|
|
26
|
+
sudo apt install libczmq-dev
|
|
55
27
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
end
|
|
59
|
-
end
|
|
28
|
+
# macOS
|
|
29
|
+
brew install czmq
|
|
60
30
|
```
|
|
61
31
|
|
|
32
|
+
Then add the gem:
|
|
62
33
|
|
|
63
|
-
|
|
34
|
+
```sh
|
|
35
|
+
gem install cztop
|
|
36
|
+
# or in Gemfile
|
|
37
|
+
gem 'cztop'
|
|
64
38
|
```
|
|
65
|
-
$ cd examples
|
|
66
|
-
$ time ./async.rb
|
|
67
|
-
<<< ["foobar #0"]
|
|
68
|
-
>>> ["FOOBAR #0"]
|
|
69
|
-
<<< ["foobar #1"]
|
|
70
|
-
>>> ["FOOBAR #1"]
|
|
71
|
-
<<< ["foobar #2"]
|
|
72
|
-
>>> ["FOOBAR #2"]
|
|
73
|
-
<<< ["foobar #3"]
|
|
74
|
-
>>> ["FOOBAR #3"]
|
|
75
|
-
<<< ["foobar #4"]
|
|
76
|
-
>>> ["FOOBAR #4"]
|
|
77
|
-
<<< ["foobar #5"]
|
|
78
|
-
>>> ["FOOBAR #5"]
|
|
79
|
-
<<< ["foobar #6"]
|
|
80
|
-
>>> ["FOOBAR #6"]
|
|
81
|
-
<<< ["foobar #7"]
|
|
82
|
-
>>> ["FOOBAR #7"]
|
|
83
|
-
<<< ["foobar #8"]
|
|
84
|
-
>>> ["FOOBAR #8"]
|
|
85
|
-
<<< ["foobar #9"]
|
|
86
|
-
>>> ["FOOBAR #9"]
|
|
87
|
-
REQ done.
|
|
88
|
-
REP done.
|
|
89
|
-
|
|
90
|
-
________________________________________________________
|
|
91
|
-
Executed in 401.51 millis fish external
|
|
92
|
-
usr time 308.44 millis 605.00 micros 307.83 millis
|
|
93
|
-
sys time 40.08 millis 278.00 micros 39.81 millis
|
|
94
39
|
|
|
95
|
-
|
|
40
|
+
## Learning ZeroMQ
|
|
96
41
|
|
|
97
|
-
|
|
42
|
+
New to ZeroMQ? See [ZGUIDE_SUMMARY.md](ZGUIDE_SUMMARY.md) — a ~30 min read covering all major patterns with working CZTop code examples.
|
|
98
43
|
|
|
99
|
-
##
|
|
44
|
+
## Quick Start
|
|
100
45
|
|
|
101
|
-
###
|
|
46
|
+
### Request / Reply
|
|
102
47
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
* CURVE security
|
|
107
|
-
* supports CZMQ DRAFT API
|
|
108
|
-
* extensive spec coverage
|
|
48
|
+
```ruby
|
|
49
|
+
require 'cztop'
|
|
50
|
+
require 'async'
|
|
109
51
|
|
|
110
|
-
|
|
52
|
+
Async do |task|
|
|
53
|
+
rep = CZTop::Socket::REP.new('inproc://example')
|
|
54
|
+
req = CZTop::Socket::REQ.new('inproc://example')
|
|
111
55
|
|
|
56
|
+
task.async do
|
|
57
|
+
msg = rep.receive
|
|
58
|
+
rep << msg.map(&:upcase)
|
|
59
|
+
end
|
|
112
60
|
|
|
113
|
-
|
|
114
|
-
|
|
61
|
+
req << 'hello'
|
|
62
|
+
puts req.receive.inspect # => ["HELLO"]
|
|
63
|
+
end
|
|
64
|
+
```
|
|
115
65
|
|
|
66
|
+
### Pub / Sub
|
|
116
67
|
|
|
117
|
-
|
|
68
|
+
```ruby
|
|
69
|
+
Async do |task|
|
|
70
|
+
pub = CZTop::Socket::PUB.new('inproc://pubsub')
|
|
71
|
+
sub = CZTop::Socket::SUB.new('inproc://pubsub')
|
|
72
|
+
sub.subscribe('') # subscribe to all
|
|
118
73
|
|
|
119
|
-
|
|
74
|
+
sleep 0.01 # allow connection to establish
|
|
120
75
|
|
|
121
|
-
|
|
76
|
+
task.async { pub << 'news flash' }
|
|
77
|
+
puts sub.receive.inspect # => ["news flash"]
|
|
78
|
+
end
|
|
79
|
+
```
|
|
122
80
|
|
|
123
|
-
|
|
81
|
+
### Push / Pull (Pipeline)
|
|
124
82
|
|
|
125
|
-
|
|
83
|
+
```ruby
|
|
84
|
+
Async do
|
|
85
|
+
push = CZTop::Socket::PUSH.new('inproc://pipeline')
|
|
86
|
+
pull = CZTop::Socket::PULL.new('inproc://pipeline')
|
|
126
87
|
|
|
127
|
-
|
|
88
|
+
push << 'work item'
|
|
89
|
+
puts pull.receive.inspect # => ["work item"]
|
|
90
|
+
end
|
|
91
|
+
```
|
|
128
92
|
|
|
129
|
-
|
|
93
|
+
## Socket Types
|
|
130
94
|
|
|
131
|
-
|
|
95
|
+
| Pattern | Classes | Direction |
|
|
96
|
+
|---------|---------|-----------|
|
|
97
|
+
| Request/Reply | `REQ`, `REP` | bidirectional |
|
|
98
|
+
| Publish/Subscribe | `PUB`, `SUB`, `XPUB`, `XSUB` | unidirectional |
|
|
99
|
+
| Pipeline | `PUSH`, `PULL` | unidirectional |
|
|
100
|
+
| Routing | `DEALER`, `ROUTER` | bidirectional |
|
|
101
|
+
| Exclusive pair | `PAIR` | bidirectional |
|
|
102
|
+
| Raw TCP | `STREAM` | bidirectional |
|
|
132
103
|
|
|
133
|
-
|
|
104
|
+
All classes live under `CZTop::Socket::`.
|
|
134
105
|
|
|
135
|
-
|
|
136
|
-
gem 'cztop'
|
|
137
|
-
```
|
|
106
|
+
## Performance
|
|
138
107
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
$ bundle
|
|
142
|
-
|
|
143
|
-
Or install it yourself as:
|
|
144
|
-
|
|
145
|
-
$ gem install cztop
|
|
146
|
-
|
|
147
|
-
### Class Hierarchy
|
|
148
|
-
|
|
149
|
-
Here's an overview of the core classes:
|
|
150
|
-
|
|
151
|
-
* [CZTop](http://www.rubydoc.info/gems/cztop/CZTop)
|
|
152
|
-
* [Actor](http://www.rubydoc.info/gems/cztop/CZTop)
|
|
153
|
-
* [Authenticator](http://www.rubydoc.info/gems/cztop/CZTop/Authenticator)
|
|
154
|
-
* [Beacon](http://www.rubydoc.info/gems/cztop/CZTop/Beacon)
|
|
155
|
-
* [Certificate](http://www.rubydoc.info/gems/cztop/CZTop/Certificate)
|
|
156
|
-
* [CertStore](http://www.rubydoc.info/gems/cztop/CZTop/CertStore)
|
|
157
|
-
* [Config](http://www.rubydoc.info/gems/cztop/CZTop/Config)
|
|
158
|
-
* [Frame](http://www.rubydoc.info/gems/cztop/CZTop/Frame)
|
|
159
|
-
* [Message](http://www.rubydoc.info/gems/cztop/CZTop/Message)
|
|
160
|
-
* [Monitor](http://www.rubydoc.info/gems/cztop/CZTop/Monitor)
|
|
161
|
-
* [Metadata](http://www.rubydoc.info/gems/cztop/CZTop/Metadata)
|
|
162
|
-
* [Proxy](http://www.rubydoc.info/gems/cztop/CZTop/Proxy)
|
|
163
|
-
* [Poller](http://www.rubydoc.info/gems/cztop/CZTop/Poller) (based on `zmq_poller_*()` functions)
|
|
164
|
-
* [Aggregated](http://www.rubydoc.info/gems/cztop/CZTop/Poller/Aggregated)
|
|
165
|
-
* [ZPoller](http://www.rubydoc.info/gems/cztop/CZTop/Poller/ZPoller)
|
|
166
|
-
* [Socket](http://www.rubydoc.info/gems/cztop/CZTop/Socket)
|
|
167
|
-
* [REQ](http://www.rubydoc.info/gems/cztop/CZTop/Socket/REQ) < Socket
|
|
168
|
-
* [REP](http://www.rubydoc.info/gems/cztop/CZTop/Socket/REP) < Socket
|
|
169
|
-
* [ROUTER](http://www.rubydoc.info/gems/cztop/CZTop/Socket/ROUTER) < Socket
|
|
170
|
-
* [DEALER](http://www.rubydoc.info/gems/cztop/CZTop/Socket/DEALER) < Socket
|
|
171
|
-
* [PUSH](http://www.rubydoc.info/gems/cztop/CZTop/Socket/PUSH) < Socket
|
|
172
|
-
* [PULL](http://www.rubydoc.info/gems/cztop/CZTop/Socket/PULL) < Socket
|
|
173
|
-
* [PUB](http://www.rubydoc.info/gems/cztop/CZTop/Socket/PUB) < Socket
|
|
174
|
-
* [SUB](http://www.rubydoc.info/gems/cztop/CZTop/Socket/SUB) < Socket
|
|
175
|
-
* [XPUB](http://www.rubydoc.info/gems/cztop/CZTop/Socket/XPUB) < Socket
|
|
176
|
-
* [XSUB](http://www.rubydoc.info/gems/cztop/CZTop/Socket/XSUB) < Socket
|
|
177
|
-
* [PAIR](http://www.rubydoc.info/gems/cztop/CZTop/Socket/PAIR) < Socket
|
|
178
|
-
* [STREAM](http://www.rubydoc.info/gems/cztop/CZTop/Socket/STREAM) < Socket
|
|
179
|
-
* [CLIENT](http://www.rubydoc.info/gems/cztop/CZTop/Socket/CLIENT) < Socket
|
|
180
|
-
* [SERVER](http://www.rubydoc.info/gems/cztop/CZTop/Socket/SERVER) < Socket
|
|
181
|
-
* [RADIO](http://www.rubydoc.info/gems/cztop/CZTop/Socket/RADIO) < Socket
|
|
182
|
-
* [DISH](http://www.rubydoc.info/gems/cztop/CZTop/Socket/DISH) < Socket
|
|
183
|
-
* [SCATTER](http://www.rubydoc.info/gems/cztop/CZTop/Socket/SCATTER) < Socket
|
|
184
|
-
* [GATHER](http://www.rubydoc.info/gems/cztop/CZTop/Socket/GATHER) < Socket
|
|
185
|
-
* [Z85](http://www.rubydoc.info/gems/cztop/CZTop/Z85)
|
|
186
|
-
* [Padded](http://www.rubydoc.info/gems/cztop/CZTop/Z85/Padded) < Z85
|
|
187
|
-
* [Pipe](http://www.rubydoc.info/gems/cztop/CZTop/Z85/Pipe)
|
|
188
|
-
* [ZAP](http://www.rubydoc.info/gems/cztop/CZTop/ZAP)
|
|
189
|
-
|
|
190
|
-
More information in the [API documentation](http://www.rubydoc.info/github/paddor/cztop).
|
|
191
|
-
|
|
192
|
-
## Documentation
|
|
193
|
-
|
|
194
|
-
The API should be fairly straight-forward to anyone who is familiar with CZMQ
|
|
195
|
-
and Ruby. The following API documentation is currently available:
|
|
196
|
-
|
|
197
|
-
* [YARD API documentation](http://www.rubydoc.info/gems/cztop) (release)
|
|
198
|
-
|
|
199
|
-
Feel free to start a [wiki](https://github.com/paddor/cztop/wiki) page.
|
|
108
|
+
Benchmarked with benchmark-ips on Linux x86_64 (CZMQ 4.2.1, ZMQ 4.3.5, Ruby 4.0.1 +YJIT):
|
|
200
109
|
|
|
201
|
-
|
|
110
|
+
#### Throughput (push/pull)
|
|
202
111
|
|
|
203
|
-
|
|
112
|
+
| | inproc | ipc | tcp |
|
|
113
|
+
|---|--------|-----|-----|
|
|
114
|
+
| **Async** | 284k/s | 17k/s | 14k/s |
|
|
115
|
+
| **Threads** | 353k/s | 25k/s | 21k/s |
|
|
204
116
|
|
|
205
|
-
|
|
206
|
-
[perf](https://github.com/paddor/cztop/blob/master/perf) directory for latency
|
|
207
|
-
and throughput measurement scripts.
|
|
117
|
+
#### Latency (req/rep roundtrip)
|
|
208
118
|
|
|
209
|
-
|
|
119
|
+
| | inproc | ipc | tcp |
|
|
120
|
+
|---|--------|-----|-----|
|
|
121
|
+
| **Async** | 49 µs | 100 µs | 107 µs |
|
|
122
|
+
| **Threads** | 113 µs | 154 µs | 168 µs |
|
|
210
123
|
|
|
211
|
-
See
|
|
124
|
+
Async fibers deliver 2.3x lower inproc latency thanks to cheap context switching. See [`bench/`](bench/) for full results and scripts.
|
|
212
125
|
|
|
126
|
+
## API Reference
|
|
213
127
|
|
|
214
|
-
|
|
128
|
+
Full [API documentation](http://www.rubydoc.info/gems/cztop).
|
|
215
129
|
|
|
216
|
-
|
|
130
|
+
## Development
|
|
217
131
|
|
|
218
|
-
|
|
219
|
-
|
|
132
|
+
```sh
|
|
133
|
+
bundle install
|
|
134
|
+
bundle exec rake
|
|
135
|
+
```
|
|
220
136
|
|
|
221
137
|
## License
|
|
222
138
|
|
|
223
|
-
|
|
224
|
-
See the [LICENSE](https://github.com/paddor/cztop/blob/master/LICENSE) file.
|
|
139
|
+
[ISC](LICENSE)
|