Interface NatsOperations
-
- All Implemented Interfaces:
public interface NatsOperationsEverything that publishes, requests or subscribes - the messaging surface, without the connection behind it.
NatsKlient implements it, and application code is usually better off naming this. A service that takes a
NatsOperationssays what it needs - to send and receive messages - rather than that it holds a connection it could close; and a dependency-injection container can bind the two separately, so only the code that owns the lifecycle can end it:single(createdAtStart = true) { NatsKlient(configure = configure).connect() } .onClose { it?.closeBlocking() } single<NatsOperations> { get<NatsKlient>() }Connecting, draining, closing and JetStream stay on NatsKlient: those belong to whoever owns the connection, not to everyone who sends a message over it.
Each typed operation appears twice. The one to call is the
reifiedextension -publish("orders", event)- which resolves the codec from the type at the call site; being an extension, it has to be imported. Every one of them delegates to the member named after it with aTypedsuffix, which takes the type as a KType value instead. That indirection is what an interface forces: areifiedtype parameter needs aninlinefunction, and an interface member cannot be inlined.The
Typedform is worth calling directly when the type arrives as a value rather than as a type argument - a listener container told at startup what to carry. Nothing checks that the KType describesT, though: a mismatch is not a compile error and not a failure at the call either, but aClassCastExceptionwherever the decoded value is finally used.
-
-
Method Summary
Modifier and Type Method Description abstract UnitpublishBytes(String subject, ByteArray data, Headers headers)Publish raw bytes for performance-critical pathsHands the message to the connection's outgoing queue and returns without waiting for the server. abstract SubscriptionHandle<Message>subscribeBytes(String subject, String queue, Integer capacity, BufferOverflow onOverflow)Subscribe to raw messages for performanceThe jnats dispatcher hands messages to a channel of capacity slots without ever suspending. abstract <T extends Any> UnitpublishTyped(String subject, T message, KType type, Headers headers)publish with the type to carry message as given as a value. abstract <Req extends Any, Resp extends Any> ResprequestTyped(String subject, Req request, KType requestType, KType responseType, Duration timeout)request with both types given as values. abstract <Req extends Any, Resp extends Any> Flow<Resp>requestManyTyped(String subject, Req request, KType requestType, KType responseType, Integer expectedResponses, Duration timeout, DecodeErrorStrategy onDecodeError)requestMany with both types given as values. abstract <T extends Any> SubscriptionHandle<T>subscribeTyped(String subject, KType type, String queue, Integer capacity, BufferOverflow onOverflow, DecodeErrorStrategy onDecodeError)subscribe with the type to decode into given as a value. abstract <T extends Any> SubscriptionHandle<TypedMessage<T>>subscribeMessagesTyped(String subject, KType type, String queue, Integer capacity, BufferOverflow onOverflow, DecodeErrorStrategy onDecodeError)subscribeMessages with the type to decode into given as a value. abstract <Req extends Any, Resp extends Any> SubscriptionHandle<TypedMessage<Req>>respondTyped(String subject, KType requestType, KType responseType, String queue, Integer capacity, BufferOverflow onOverflow, DecodeErrorStrategy onDecodeError, SuspendFunction1<Req, Resp> handler)respond with both types given as values. -
-
Method Detail
-
publishBytes
abstract Unit publishBytes(String subject, ByteArray data, Headers headers)
Publish raw bytes for performance-critical paths
Hands the message to the connection's outgoing queue and returns without waiting for the server. Thread-safe, and needs no dispatcher of its own.
It is not unconditionally non-blocking, though. The outgoing queue is bounded - KlientConfigBuilder.maxMessagesInOutgoingQueue, 5000 by default - and a publisher faster than the connection can write will fill it. jnats then waits for room, and gives up with a eu.vstoyanov.natsy.exception.NatsyConnectionException rather than blocking indefinitely, so under sustained backpressure a publish can park the calling thread for seconds. Set KlientConfigBuilder.discardMessagesWhenOutgoingQueueFull to drop the message instead of waiting.
- Parameters:
subject- The NATS subject to publish todata- The raw byte data to publishheaders- Optional headers to include
-
subscribeBytes
abstract SubscriptionHandle<Message> subscribeBytes(String subject, String queue, Integer capacity, BufferOverflow onOverflow)
Subscribe to raw messages for performance
The jnats dispatcher hands messages to a channel of capacity slots without ever suspending. The default Channel.UNLIMITED mirrors the unbounded queue jnats keeps for the dispatcher itself, so no message is ever dropped — at the cost of unbounded memory growth if the collector cannot keep up.
Bound the buffer with capacity to trade delivery for memory. Because the dispatcher callback cannot suspend, BufferOverflow.SUSPEND on a full bounded buffer means the message is dropped and logged at WARN; BufferOverflow.DROP_OLDEST and BufferOverflow.DROP_LATEST drop silently, by definition.
The buffer is applied inside the flow, so a
.buffer()on SubscriptionHandle.messages fuses into the same channel instead of adding a second one: a non-SUSPEND overflow policy replaces both settings, while a plain.buffer(n)cannot shrink an unbounded buffer.The flow ends when its collector is cancelled, when NatsKlient.close is called, and when the connection itself reaches CLOSED - a NatsKlient.drain, or jnats giving up reconnecting - so a subscription collected for the klient's whole lifetime completes rather than hanging on a connection that is no longer there.
Example:
val telemetry = klient.subscribeBytes("telemetry", capacity = 128, onOverflow = BufferOverflow.DROP_OLDEST) launch { telemetry.messages.collect { msg -> ... } } telemetry.started()- Parameters:
subject- The NATS subject to subscribe toqueue- Optional queue group name for load balancingcapacity- Delivery channel capacity, Channel.UNLIMITED by default: positive, Channel.CONFLATED or Channel.BUFFEREDonOverflow- What to do when a bounded delivery channel is full.- Returns:
a SubscriptionHandle; SubscriptionHandle.started is the readiness rendezvous
-
publishTyped
abstract <T extends Any> Unit publishTyped(String subject, T message, KType type, Headers headers)
publish with the type to carry message as given as a value.
- Parameters:
type- the type to resolve a codec from, which has to beT's
-
requestTyped
abstract <Req extends Any, Resp extends Any> Resp requestTyped(String subject, Req request, KType requestType, KType responseType, Duration timeout)
request with both types given as values.
- Parameters:
requestType- the type to resolve the request codec from, which has to beReq'sresponseType- the type to resolve the response codec from, which has to beResp's
-
requestManyTyped
abstract <Req extends Any, Resp extends Any> Flow<Resp> requestManyTyped(String subject, Req request, KType requestType, KType responseType, Integer expectedResponses, Duration timeout, DecodeErrorStrategy onDecodeError)
requestMany with both types given as values.
- Parameters:
requestType- the type to resolve the request codec from, which has to beReq'sresponseType- the type to resolve the response codec from, which has to beResp's
-
subscribeTyped
abstract <T extends Any> SubscriptionHandle<T> subscribeTyped(String subject, KType type, String queue, Integer capacity, BufferOverflow onOverflow, DecodeErrorStrategy onDecodeError)
subscribe with the type to decode into given as a value.
- Parameters:
type- the type to resolve a codec from, which has to beT's
-
subscribeMessagesTyped
abstract <T extends Any> SubscriptionHandle<TypedMessage<T>> subscribeMessagesTyped(String subject, KType type, String queue, Integer capacity, BufferOverflow onOverflow, DecodeErrorStrategy onDecodeError)
subscribeMessages with the type to decode into given as a value.
- Parameters:
type- the type to resolve a codec from, which has to beT's
-
respondTyped
abstract <Req extends Any, Resp extends Any> SubscriptionHandle<TypedMessage<Req>> respondTyped(String subject, KType requestType, KType responseType, String queue, Integer capacity, BufferOverflow onOverflow, DecodeErrorStrategy onDecodeError, SuspendFunction1<Req, Resp> handler)
respond with both types given as values.
Left to the implementation, unlike the shape of the flow it returns, which is fixed: subscribeMessagesTyped with the reply folded in. What an implementation adds is the response codec, resolved before the handle exists - only something holding a registry can do that, and respond's
@throwspromises it.- Parameters:
requestType- the type to resolve the request codec from, which has to beReq'sresponseType- the type to resolve the response codec from, which has to beResp's
-
-
-
-