Class NatsKlient
-
- All Implemented Interfaces:
-
java.lang.AutoCloseable
public final class NatsKlient implements AutoCloseable
Main entry point for NATS messaging with Kotlin-first API
This class manages the NATS connection lifecycle and provides access to messaging operations through the NatsScope.
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description public classNatsKlient.Companion
-
Field Summary
Fields Modifier and Type Field Description private final NatsScopescopeprivate final Connectionconnectionprivate final Statisticsstatisticspublic final static NatsKlient.CompanionCompanion
-
Method Summary
Modifier and Type Method Description final NatsScopegetScope()Persistent scope for long-lived operations (subscriptions, consumers, etc. final ConnectiongetConnection()Direct access to the underlying NATS connection for advanced use cases final StatisticsgetStatistics()Access to connection statistics final <T extends Any> Tsession(SuspendFunction1<NatsScope, T> block)Execute operations against a NatsScope whose lifetime is exactly blockThe scope owns a child Job of the calling coroutine, so everything launched into it — subscriptions above all — is cancelled and awaited when block returns, before the scope's jnats dispatchers are closed. final Booleandrain(Duration timeout)Gracefully drain the connection, then close itSuspends until the drain has actually finished. final BooleancloseGracefully(Duration timeout)Drain, then close: the complete shutdown sequence in one calldrain delivers what is already in flight and closes the connection; close then cancels scope and releases its dispatchers. final BooleancloseBlocking(Duration timeout)closeGracefully for callers that cannot suspendBlocks the calling thread for up to timeout on the drain. Unitclose()Cancel everything running on scope and close the connection immediatelycloseGracefully is the graceful counterpart: it drains first, so nothing in flight is lost. -
-
Method Detail
-
getScope
final NatsScope getScope()
Persistent scope for long-lived operations (subscriptions, consumers, etc.)
This scope lives for the entire lifetime of the NatsKlient instance and is cancelled by close, so nothing launched into it outlives the klient.
Use this for:
Long-lived subscriptions that should persist for the application lifetime
Publishing messages without creating a new scope each time
JetStream consumers that need to stay active
Example:
klient.scope.subscribe<Event>("events").messages .onEach { processEvent(it) } .launchIn(applicationScope)
-
getConnection
final Connection getConnection()
Direct access to the underlying NATS connection for advanced use cases
-
getStatistics
final Statistics getStatistics()
Access to connection statistics
-
session
final <T extends Any> T session(SuspendFunction1<NatsScope, T> block)
Execute operations against a NatsScope whose lifetime is exactly block
The scope owns a child Job of the calling coroutine, so everything launched into it — subscriptions above all — is cancelled and awaited when block returns, before the scope's jnats dispatchers are closed. Work that must outlive the call belongs on scope instead.
This opens a scope; it does not close the klient. The name is deliberately not
use: as a member it would win overload resolution over the stdlibAutoCloseable.usethis class now supports, soklient.use { }would silently mean "open a scope" rather than "close when done".klient.session { subscribe<Event>("events").messages.onEach { handle(it) }.launchIn(this) delay(1.minutes) // the subscription collects until the block returns, then stops }
-
drain
final Boolean drain(Duration timeout)
Gracefully drain the connection, then close it
Suspends until the drain has actually finished. jnats only unsubscribes and flushes before its Connection.drain returns — delivering the remaining in-flight messages, blocking further publishing, doing a last flush and closing the connection all happen on a background thread, and only the returned future tells you when that is done. This awaits that future, so once this returns it is safe to exit the process without losing messages.
Draining closes the connection, so the klient is not reusable afterwards. close is still worth calling to release the scope-side resources; it returns immediately on an already-closed connection. closeGracefully is that pair in one call.
- Parameters:
timeout- budget for the whole drain.- Returns:
trueif every subscription drained within timeout,falseif the timeout forced the close. Alsotruewhen the connection was already closed and there was nothing to do.
-
closeGracefully
final Boolean closeGracefully(Duration timeout)
Drain, then close: the complete shutdown sequence in one call
drain delivers what is already in flight and closes the connection; close then cancels scope and releases its dispatchers. The order matters — cancelling first would kill the subscriptions the drain exists to deliver to.
The klient always ends up closed, even if the drain fails or the caller is cancelled mid-way.
Drain waits for delivery, not for your handlers: a collector on scope that is still processing its last message when the drain finishes is cancelled like any other. Work that has to finish belongs in front of this call.
-
closeBlocking
final Boolean closeBlocking(Duration timeout)
closeGracefully for callers that cannot suspend
Blocks the calling thread for up to timeout on the drain. That is what non-suspending shutdown hooks need — Koin's
onClose, a JVM shutdown hook, a KtorMonitoringEventhandler — where the process must not exit until the drain has finished.From inside a coroutine closeGracefully is the one to call: this parks the thread it runs on for the whole drain.
-
close
Unit close()
Cancel everything running on scope and close the connection immediately
closeGracefully is the graceful counterpart: it drains first, so nothing in flight is lost.
Cancellation is signalled, not awaited: close cannot suspend, so a coroutine that is still unwinding on scope may briefly outlive the call.
The cancellation comes first so that work still touching the connection observes cancellation rather than an I/O failure against a connection pulled out from under it.
Idempotent, and safe on a klient whose scope was never touched: an unused scope is not created just to be torn down.
-
-
-
-