v0.3.0
This release is almost entirely about performance. The client was benchmarked
head-to-head against the official Java client (jnats) across core pub/sub,
JetStream, and Object Store workloads, and the hot paths were rebuilt based on
what the profiles showed. There are no public API changes — everything
below is internal.
Performance
Core pub/sub
- The protocol parser keeps a single flat array carry instead of an immutable
chunk queue, fixing an O(n²) scan under streaming load — 2.4× parser
throughput and −82% allocations in JMH, ~+40% end-to-end receive (#18) - Publishes enqueue a small write descriptor instead of building a combined
header+payload array per message; the single writer fiber assembles batches
into one reused buffer and flushes them in one socket write — per-publish
allocation is now constant at 112 B regardless of payload size (#20, #21, #22) - The receive path builds the user-facing message once, directly in the parser,
instead of materializing an intermediate frame that gets re-wrapped (#23) - Sends take a lock-free fast path while the connection is online (#19)
- Sockets are read in 64 KiB requests instead of fs2-io's 8 KiB default,
cutting async read round-trips 8× on large-payload streams (#26) - Internal bounded queues stay on cats-effect's lock-free implementation at
any capacity.Queue.boundedsilently degrades to a CAS-retry queue at
capacities ≥ 65534, which cost >30% of client CPU under sustained load with
largequeueCapacitysettings — high-capacity configs are now ~2× faster
under CPU pressure (#24)
JetStream
consumeprocesses inbox messages chunk-at-a-time instead of one effect per
message: 2.1× consume throughput (#25)
Object Store
- GET benefits from the larger socket reads and now hashes chunks without
copying them — streaming GET reaches parity with jnats at steady state
(~1.3 GB/s in our benchmarks) (#26)
Other changes
- New documentation site: https://thatscalaguy.github.io/fs2-nats (#17)
- README: expanded feature overview and compatibility matrix
- Apache 2.0 LICENSE file added to the repository
- Test library updates (#16)
Compatibility
- Binary compatible with 0.2.x (MiMa-checked); no source changes required
- Scala 3, cats-effect 3.6, fs2 3.13; JDK 11+
What's Changed
- docs: add sbt-typelevel-site documentation site by @ThatScalaGuy in #17
- Test library updates by @ThatScalaGuy in #16
- perf(parser): flat-array incremental decoder (fixes O(n²) control-line scan) by @ThatScalaGuy in #18
- perf(client): skip the connRef.modify CAS on the Online publish path by @ThatScalaGuy in #19
- perf(transport): reuse the writer coalescing buffer across drains by @ThatScalaGuy in #20
- perf(transport): drop the per-publish Some box from the write queue by @ThatScalaGuy in #21
- perf(publish): enqueue a write descriptor instead of a per-publish combined array by @ThatScalaGuy in #22
- perf(receive): build the user NatsMessage once on the MSG/HMSG data path by @ThatScalaGuy in #23
- perf(queues): keep hot-path queues on cats-effect's lock-free implementations at any capacity by @ThatScalaGuy in #24
- perf(jetstream): process pull-consume deliveries a chunk at a time by @ThatScalaGuy in #25
- perf(receive): 64 KiB socket reads + copy-free Object Store GET digest by @ThatScalaGuy in #26
Full Changelog: v0.2.0...v0.3.0