Commit d3bf9ae
Fix nats-pure migration regressions; harden + speed up client and server (0.13.1)
Fixes a production 500 (RPC_ERROR / "EOF") and a broad set of related issues, all
of the same class -- assumptions left over from the JNats -> nats-pure migration
in 0.13.0 that became silently wrong -- then hardens and speeds up the client
muxer and the server. Every change ships with negative/regression specs;
benchmarks prove the performance and resilience wins. Full suite: 190 examples,
0 failures.
Client / transport
- Retry the transport errors nats-pure and the socket layer actually raise
(EOFError, IOError, Errno::ECONNRESET/EPIPE/ECONNREFUSED/ETIMEDOUT,
NATS::IO::ConnectionClosedError, ConnectionPool::TimeoutError, and
java.io.IOException on JRuby) via Errors::RETRYABLE_TRANSPORT_ERRORS, routed
through the reconnect_delay loop. The 0.13.0 collapse of IOException to the
never-raised MriIOException had turned this into dead code.
- Bounded + jittered retry: PB_NATS_CLIENT_MAX_RETRIES and
PB_NATS_CLIENT_RECONNECT_DELAY_SPLAY_LIMIT; reconnect sleep is jittered so a
fleet doesn't reconnect in lockstep.
- Removed the dead :disable_reconnect_buffer connect option; connection_options
now forwards only nats-pure-recognized keys.
- Connection lifecycle: register callbacks before connect; close the half-open
client on a failed handshake so reader/flusher threads aren't leaked.
Response muxer (performance + robustness)
- Dropped the per-message pending_size lock from the dispatch hot path (disable
the byte-based slow-consumer limit, rely on the message-count limit):
~2.6x faster per message and removes the pending_size-drift bug that could
silently drop all responses.
- Dispatch loop no longer busy-spins during a restart window (nil @resp_sub
guard); self-healing crash counter is a Concurrent::AtomicFixnum that decays
once healthy (a plain Integer lost ~45% of updates under concurrent crashes).
Server (performance + reliability + observability)
- Parallelized request intake across PB_NATS_SERVER_SUBSCRIPTION_HANDLERS threads
(default processor_count on JRuby, 1 on CRuby), each with per-thread
self-healing. NATS queue-group semantics and subscription counts are unchanged
-- each request is still delivered to exactly one consumer. ~8.4x intake
throughput; head-of-line stall ~505ms -> ~0.5ms at 8 handlers.
- Handler observability, long ops first-class: handlers are never aborted;
in-flight tracking + new notifications (inflight_count, inflight_oldest_age_ms,
overdue_handler_count, handler_overdue, pending_intake_queue_size, slow_handler
(opt-in), thread_pool_saturated, subscription_handler_count/_crashed). A handler
is "overdue" only once it outlives the client's response_timeout
(PB_NATS_SERVER_HANDLER_OVERDUE_MS, default 65s). Durations use a monotonic clock.
- Fail the caller fast: publish an encoded RPC_ERROR response (via PbError) when a
request fails after it has been ACKed.
- Thread pool: wait_for_termination prunes under the mutex and returns a real
result; replenish respawns workers killed by a non-StandardError; shutdown drain
timeout tracks handler_overdue so long handlers aren't killed mid-flight.
- Error callbacks dispatch off the nats read/flush thread via a bounded executor.
Config
- No crash when the yml has no section for the current environment (or is empty).
- YAML safe_load(aliases: true) instead of unsafe_load.
Refactors / quality
- Single source of truth for the monotonic clock (Protobuf::Nats.monotonic_time),
the instrumentation suffix (Protobuf::Nats.instrument), and the self-healing
backoff formula (Protobuf::Nats.crash_backoff_seconds).
- Reuse Protobuf::Rpc::PbError for the server error response.
Docs / benchmarks / tests
- README (env vars, How it works, Resilience, Benchmarks) and CHANGELOG updated.
- bench/muxer_resilience_bench.rb, bench/server_intake_bench.rb, and an opt-in
bench/soak.rb (spawns nats-server, bounces it mid-run, asserts recovery).
- wait_until spec helper for deterministic concurrency tests.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>1 parent c77a5e5 commit d3bf9ae
24 files changed
Lines changed: 1619 additions & 222 deletions
File tree
- bench
- lib/protobuf
- nats
- spec
- protobuf
- nats
- support
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
3 | 23 | | |
4 | 24 | | |
5 | 25 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
39 | 39 | | |
40 | 40 | | |
41 | 41 | | |
42 | | - | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
43 | 59 | | |
44 | 60 | | |
45 | 61 | | |
| |||
50 | 66 | | |
51 | 67 | | |
52 | 68 | | |
53 | | - | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
54 | 74 | | |
55 | 75 | | |
56 | 76 | | |
| |||
93 | 113 | | |
94 | 114 | | |
95 | 115 | | |
| 116 | + | |
| 117 | + | |
96 | 118 | | |
97 | 119 | | |
98 | 120 | | |
| |||
162 | 184 | | |
163 | 185 | | |
164 | 186 | | |
165 | | - | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
166 | 191 | | |
167 | | - | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
168 | 229 | | |
169 | 230 | | |
170 | 231 | | |
171 | 232 | | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
172 | 245 | | |
173 | 246 | | |
174 | 247 | | |
| |||
0 commit comments