Skip to content

v0.4.0

Latest

Choose a tag to compare

@ThatScalaGuy ThatScalaGuy released this 25 Aug 15:46
· 5 commits to main since this release

The headline of this release is fs2.nats.micro — typed NATS micro services
implementing ADR-32.
Alongside it, another round of hot-path work landed across core pub/sub, JetStream,
and Object Store, and 0.4 starts a new binary-compatibility series.

Micro services (fs2.nats.micro)

  • An endpoint is described once as a plain Rpc[P, I, E, O] value — subject pattern
    with typed captures, request payload, typed error, response payload — and interpreted
    on both sides: rpc.handle(...) inside a NatsService, Micro(client).call(rpc)(...)
    from the caller. Definitions can live in a shared module (#57)
  • Subject patterns are checked at compile time: pattern["orders.*"].bind[OrderId]
    rejects malformed literals, computes the capture arity, and binds captures through
    TokenCodecs (String, Int, Long, UUID, or your own)
  • Payloads via Payload.empty / bytes / string / json[A] (jsoniter-scala),
    with optional schema text published in the endpoint INFO metadata
  • Errors are typed end to end: handlers return F[Either[E, O]], errors travel as
    ADR-32 error headers and come back as Left(E) at the caller — transport failures
    are the only thing raised in F
  • Full ADR-32 discovery: every instance answers $SRV.PING / INFO / STATS in all
    nine subject forms with the standard response types, so nats micro CLI tooling
    works out of the box; per-endpoint stats are also available locally via
    NatsService#stats
  • Instances load-balance through a queue group by default; service and endpoint
    metadata per ADR-33; request headers are visible to handlers, and response headers
    can be set via Reply

The module ships inside the fs2-nats artifact and adds no new dependency
(jsoniter-scala was already on the classpath for JetStream). See
docs/micro.md
for the full tour.

Performance

  • Dialled sockets now set TCP_NODELAY, removing Nagle-induced latency (up to
    ~40 ms per round trip) from request/reply; socket options are configurable via
    the new TransportConfig.socketOptions (#44)
  • JetStream.publishAsync — and Object Store put / KV putAsync on top of it —
    no longer starts a supervised fiber per message; correlation is registered up
    front and the reply completes on the shared inbox drain fiber (#47)
  • Request correlation moved from four CAS loops over an immutable-map Ref to a
    ConcurrentHashMap plus AtomicLong, so pipelined request/reply scales instead
    of contending on one serialization point (#49)
  • Subscription lookup on the delivery path uses a primitive-keyed LongMap and a
    single volatile read instead of boxing the sid and reading two Refs per
    message (#50)
  • JetStream API replies are decoded in place in a single jsoniter pass instead of
    a payload copy plus two passes per PubAck (#51)
  • Object Store put feeds SHA-256 by wrapping each chunk's backing arrays instead
    of flattening them, dropping the extra full copy of all object data on the way
    to the wire (#53)

Compatibility

  • 0.4 starts a new early-semver series: not binary compatible with 0.3.x,
    recompile against 0.4.0. Source-level, typical users need no changes
  • TransportConfig gained a socketOptions field (default: TCP_NODELAY on for
    sockets the library dials — override socketOptions to opt out). Named-argument
    construction is unaffected; only full-arity positional construction needs the
    new argument
  • The NatsClient trait gained a package-private abstract method, so hand-written
    implementations of the trait outside fs2.nats (e.g. test stubs) no longer
    compile — delegate to a real client instead
  • Scala 3, cats-effect 3.7, fs2 3.13; JDK 11+
  • Dependency refresh: jsoniter-scala 2.38.17 → 2.40.1; munit 1.3.5, sbt 1.12.15,
    scalafmt 3.11.5 (test/build-scoped only)

What's Changed

Full Changelog: v0.3.1...v0.4.0