Skip to content

Kotlin STREAM Session Public Interface

Interface table of contents · Java STREAM Session · Session Actor Dispatch

The Kotlin session lifecycle and coroutine handler use the Java session contract unchanged. The builder member that turns on Actor dispatch is enableActorDispatch(), which takes no MeshName argument. Startup requires a Mesh whose object role is Client or Server, and a Location Store. The global ActorId determines current authority and Mesh.

Session bind takes an ActorRef once. There's no bind overload taking only a local Actor instance or ActorId. If there's no current mapping at bind, NotFound; if the generation differs, InvalidOperation; if in the pre-commit seal window, Unavailable. The framework doesn't perform hidden retry or a local fallback.

Session send/reply, bound session send, and Session Actor relay return a Kotlin one-way wrapper. The application only waits for local STREAM queue admission with await(): Unit, and doesn't directly use Java's CompletionStage and submission result type. If the queue is full, it waits until the send timeout, and timeout, cancellation, route break, and runtime shutdown complete with an exception.

Java's ZLinkSessionActor.notifyDisconnected() is used as a logical notification while the connection is kept. After bind, relay/disconnect use the per-Actor stored route and don't query the Location Store per message. A physical disconnect has the framework perform an automatic all-settled notification to every current binding, running the Spot callback at most once per specified binding identity. A relocation route update is only allowed on the same ObjectGeneration. A logical notification also runs the binding callback at most once, then commits the binding as a tombstone and removes it after terminal. The physical STREAM connection and Actor/Spot membership are kept, and no new public Unbind API is provided. Rebind completes as soon as the new identity becomes current and does not wait for the previous session. The previous session may notify the client in onActorBindingReplacedSuspending(...). The framework closes the connection 100 ms after the callback reaches a successful or failed terminal; an empty outbound queue does not shorten this delay. Callback or close failure doesn't remove the new binding or restore the old one. Java's ZLinkSessionActor.ref() returns ActorRef. Session–Actor binding §8.2 owns relocation route updates for a bound Session.

Implementation difference Current state
Session Actor binding replacement None. The Kotlin bridge connects the suspending callback (onActorBindingReplacedSuspending), and the JVM runtime provides the command 51 codec and the non-blocking 100 ms close timer.

STREAM Socket Message Size

Kotlin uses Java's configureSocket().setMaxMessageSize(...) contract unchanged. The default is 64 KiB, and it applies only to complete client-to-server messages received by a StreamNode through Core STREAM. The size is header bytes plus payload bytes, excluding the 6-byte prefix. 0 means no Framework limit and a negative value is a startup error. An over-limit message isn't delivered to the handler; the server records EMSGSIZE and closes the connection. The Framework limit doesn't apply to server-to-client outbound messages.

Kotlin Source Signature

interface ZLinkSuspendingTypedSessionPacketHandler<
 TSessionContext : ZLinkSessionContext,
 TMessage : Any,
> {
 fun packetName(): String
 fun messageType(): Class<TMessage>
 suspend fun handle(
 context: TSessionContext,
 dispatch: ZLinkSessionDispatchContext,
 message: TMessage,
 )
}

abstract class ZLinkSuspendingSession : ZLinkSession {
 abstract override fun context(): ZLinkSessionContext
 protected open suspend fun onConnectedSuspending()
 protected open suspend fun onDisconnectedSuspending()
 protected open suspend fun onActorBindingReplacedSuspending(actorId: String)
 protected open suspend fun onErrorSuspending(error: ZLinkStreamError)
 protected open suspend fun onDispatchSuspending(
 dispatch: ZLinkSessionDispatchContext,
 payload: ZLinkMessage,
 )
}

suspend fun ZLinkSessionActors.bindOrGetActor(
 actor: ActorRef,
): ZLinkSessionActor

interface ZLinkKotlinSessionSendCall {
 fun metadata(key: String, value: String): ZLinkKotlinSessionSendCall
 fun compress(): ZLinkKotlinSessionSendCall
 fun timeout(timeout: Duration): ZLinkKotlinSessionSendCall
 suspend fun await()
}

interface ZLinkKotlinSessionReplyCall {
 fun compress(): ZLinkKotlinSessionReplyCall
 suspend fun await()
}

interface ZLinkKotlinSessionClient {
 fun send(message: Any): ZLinkKotlinSessionSendCall
 fun reply(message: Any): ZLinkKotlinSessionReplyCall
}

interface ZLinkKotlinSessionActor {
 fun relay(message: ZLinkMessage): ZLinkKotlinSubmissionCall
 fun relay(
 dispatch: ZLinkSessionDispatchContext,
 message: ZLinkMessage,
 ): ZLinkKotlinSubmissionCall
}

interface ZLinkKotlinBoundSession {
 fun send(message: Any): ZLinkKotlinMessageSendCall
}

Generated JVM Signature

public interface systems.zlink.framework.kotlin.ZLinkSuspendingTypedSessionPacketHandler<TSessionContext extends systems.zlink.framework.streams.ZLinkSessionContext, TMessage> {
 public abstract java.lang.String packetName();
 public abstract java.lang.Class<TMessage> messageType();
 public abstract java.lang.Object handle(TSessionContext, systems.zlink.framework.streams.ZLinkSessionDispatchContext, TMessage, kotlin.coroutines.Continuation<? super kotlin.Unit>);
}
public abstract class systems.zlink.framework.kotlin.ZLinkSuspendingSession implements systems.zlink.framework.streams.ZLinkSession {
 public systems.zlink.framework.kotlin.ZLinkSuspendingSession();
 public abstract systems.zlink.framework.streams.ZLinkSessionContext context();
 public final java.util.concurrent.CompletionStage<java.lang.Void> onConnected();
 public final java.util.concurrent.CompletionStage<java.lang.Void> onDisconnected();
 public final java.util.concurrent.CompletionStage<java.lang.Void> onActorBindingReplaced(java.lang.String);
 public final java.util.concurrent.CompletionStage<java.lang.Void> onError(systems.zlink.framework.streams.ZLinkStreamError);
 public final java.util.concurrent.CompletionStage<java.lang.Void> onDispatch(systems.zlink.framework.streams.ZLinkSessionDispatchContext, systems.zlink.framework.messaging.ZLinkMessage);
}
public final class systems.zlink.framework.kotlin.ZLinkFrameworkExtensionsKt {
 public static final java.lang.Object bindOrGetActor(systems.zlink.framework.streams.ZLinkSessionActors, systems.zlink.framework.actors.ActorRef, kotlin.coroutines.Continuation<? super systems.zlink.framework.streams.ZLinkSessionActor>);
}
public interface systems.zlink.framework.kotlin.ZLinkKotlinSessionSendCall {
 public abstract systems.zlink.framework.kotlin.ZLinkKotlinSessionSendCall metadata(java.lang.String, java.lang.String);
 public abstract systems.zlink.framework.kotlin.ZLinkKotlinSessionSendCall compress();
 public abstract systems.zlink.framework.kotlin.ZLinkKotlinSessionSendCall timeout-LRDsOJo(long);
 public abstract java.lang.Object await(kotlin.coroutines.Continuation<? super kotlin.Unit>);
}
public interface systems.zlink.framework.kotlin.ZLinkKotlinSessionReplyCall {
 public abstract systems.zlink.framework.kotlin.ZLinkKotlinSessionReplyCall compress();
 public abstract java.lang.Object await(kotlin.coroutines.Continuation<? super kotlin.Unit>);
}
public interface systems.zlink.framework.kotlin.ZLinkKotlinSessionClient {
 public abstract systems.zlink.framework.kotlin.ZLinkKotlinSessionSendCall send(java.lang.Object);
 public abstract systems.zlink.framework.kotlin.ZLinkKotlinSessionReplyCall reply(java.lang.Object);
}
public interface systems.zlink.framework.kotlin.ZLinkKotlinSessionActor {
 public abstract systems.zlink.framework.kotlin.ZLinkKotlinSubmissionCall relay(systems.zlink.framework.messaging.ZLinkMessage);
 public abstract systems.zlink.framework.kotlin.ZLinkKotlinSubmissionCall relay(systems.zlink.framework.streams.ZLinkSessionDispatchContext, systems.zlink.framework.messaging.ZLinkMessage);
}
public interface systems.zlink.framework.kotlin.ZLinkKotlinBoundSession {
 public abstract systems.zlink.framework.kotlin.ZLinkKotlinMessageSendCall send(java.lang.Object);
}

ZLinkKotlinSessionSendCall.timeout(...) only shortens this send's admission wait. Omission uses Java's STREAM socket send timeout; specifying it uses the shorter of the two, so it cannot extend the socket timeout. The duration is positive and must round up into 1..Int.MAX_VALUE milliseconds. Expiry completes terminal-once as ZLinkFrameworkErrorKind.DEADLINE_EXCEEDED and does not start later admission or replay. Coroutine cancellation keeps the existing Kotlin wait-cancellation meaning, and the reply call doesn't provide this modifier.