Kotlin Configuration And Host Public Interface¶
Interface table of contents · Java Configuration · MeshNode Common Contract
A Kotlin application directly uses the Java builder. The Kotlin DSL is
only provided when a receiver and reified type genuinely reduce
duplication, and doesn't create a role, factory default, or allocation
provider that isn't in the Java contract. So ClientServer's Client-only
connect and the intent merging per Server RID/lifecycle generation, and
fanout's Subscriber-only connect and the ban on mixing automatic/manual
subscriber, apply the same contract as
Java Configuration
unchanged. On the same ClientServer ChannelName, the Java builder's
client() and server() can each be registered once, without adding a
separate Kotlin DSL or public API. The two roles share one topology
through separate registrations under the (ChannelName, Role) key, and
a duplicate of the same role is a startup error. A local Server is also
selected under the same readiness/weight/drain conditions as a remote
Server, without local priority or calling a handler directly.
Automatic RouteMesh compares RID in canonical byte order, and only the MeshNode with the smaller RID connects to the counterpart endpoint. A manual topology can connect from one or both sides depending on application endpoint configuration. If bidirectional connection or automatic discovery contention/a stale snapshot creates a duplicate candidate, handshake and admission check the same RID and lifecycle generation and keep only one in ready state.
A peer connection isn't needed only when both MeshNodes are Object
Client and neither has RouteMesh Channel Server membership. The same
applies when only Channel Client membership is registered. If either
side has Channel Server membership, including weight 0, a connection
is needed. ClientServer and classic fanout are separate physical
topologies, so they aren't included in this judgment.
A MeshNode's object role is
one of None, Client, Server. Not calling objects() means
None; client() provides an outbound manager and resolve; server()
provides Client capability plus factory/
Entry registration together. Client and Server need a Location Store.
None has no object manager or factory. Selecting a duplicate role on
one node is a startup configuration error. A RouteMesh Channel Server
can also be registered on an Object Client, but an application Node
direct handler can't be registered. Specifying an Object Client RID as
a Node direct target ends as not-found without switching to a different
RID.
ZLinkFrameworkOptions.addLocationStore(...) and
addRelocationStore(...) use the Java public member unchanged. If even
one factory selected recreateOnRelocation() or preserveStateWith(...),
or even one Instance Spot factory exists, exactly one Relocation Store
must be registered. A missing or duplicate registration is a
configuration error before socket bind. A Relocation Store isn't
required for a same-node configuration with no
Instance Spot
factory that only selected disableRelocation(). A Kotlin DSL or
Redis-specific registration helper bundling both capabilities isn't
provided. The application state/queue/timer handoff payload of a
cross-node Actor/Spot move isn't
stored in the Relocation Store. The source keeps the payload in memory
and transfers it as chunks directly over the source–target ordered mesh
connection, and source memory is the restore origin. The Relocation
Store keeps owning the Instance Spot cold activation record and the
terminal record of a pending request completed after relocation, so the
registration requirement above is kept. A
same-node Actor join doesn't create a relocation payload, and a
cross-node move on a factory that selected disableRelocation() is
rejected before capture.
The following Java builder members are called directly from Kotlin with the same JVM signature, without a property conversion.
public enum systems.zlink.framework.configuration.ZLinkCoreHwmProfile {
COMPACT,
LOW_LATENCY,
BALANCED,
THROUGHPUT
}
public enum systems.zlink.framework.configuration.ZLinkApplicationJobQueueProfile {
COMPACT,
LOW_LATENCY,
BALANCED,
THROUGHPUT
}
public interface systems.zlink.framework.configuration.ZLinkDispatchOptions {
public abstract systems.zlink.framework.configuration.ZLinkUnhandledDispatchOptions unhandled();
public abstract systems.zlink.framework.configuration.ZLinkDiagnosticsOptions diagnostics();
public abstract systems.zlink.framework.configuration.ZLinkDispatchOptions messageFlow(systems.zlink.framework.configuration.ZLinkMessageFlowLogMode);
public abstract systems.zlink.framework.configuration.ZLinkDispatchOptions traceSampleRate(double);
public abstract systems.zlink.framework.configuration.ZLinkDispatchOptions includeMessageSizes(boolean);
}
public interface systems.zlink.framework.configuration.ZLinkInboundDispatchOptions {
public abstract java.util.OptionalLong coreHwmMemoryLimitBytes();
public abstract void setCoreHwmMemoryLimitBytes(long);
public abstract java.util.OptionalLong coreHwmBudgetBytes();
public abstract void setCoreHwmBudgetBytes(long);
public abstract systems.zlink.framework.configuration.ZLinkCoreHwmProfile coreHwmProfile();
public abstract void setCoreHwmProfile(systems.zlink.framework.configuration.ZLinkCoreHwmProfile);
public abstract systems.zlink.framework.configuration.ZLinkApplicationJobQueueProfile applicationJobQueueProfile();
public abstract void setApplicationJobQueueProfile(systems.zlink.framework.configuration.ZLinkApplicationJobQueueProfile);
public abstract java.util.OptionalLong maxQueuedApplicationJobs();
public abstract void setMaxQueuedApplicationJobs(long);
public abstract int applicationJobQueuePauseThresholdPercent();
public abstract void setApplicationJobQueuePauseThresholdPercent(int);
public abstract int applicationJobQueueResumeThresholdPercent();
public abstract void setApplicationJobQueueResumeThresholdPercent(int);
}
public interface systems.zlink.framework.locations.ZLinkLocationOptions {
public abstract java.time.Duration ownerLeaseRenewInterval();
public abstract void setOwnerLeaseRenewInterval(java.time.Duration);
public abstract java.time.Duration ownerLeaseTtl();
public abstract void setOwnerLeaseTtl(java.time.Duration);
public abstract java.time.Duration pollingInterval();
public abstract void setPollingInterval(java.time.Duration);
public abstract java.time.Duration storeFailureGrace();
public abstract void setStoreFailureGrace(java.time.Duration);
public abstract java.time.Duration ownerLeaseFencingMargin();
public abstract void setOwnerLeaseFencingMargin(java.time.Duration);
public abstract java.time.Duration ownerLeaseRenewTimeout();
public abstract void setOwnerLeaseRenewTimeout(java.time.Duration);
public abstract java.time.Duration routeCacheMaxAge();
public abstract void setRouteCacheMaxAge(java.time.Duration);
public abstract java.time.Duration messageFollowDuration();
public abstract void setMessageFollowDuration(java.time.Duration);
public abstract java.time.Duration sessionRelocationSealTimeout();
public abstract void setSessionRelocationSealTimeout(java.time.Duration);
public abstract long relocationPayloadChunkLimitBytes();
public abstract void setRelocationPayloadChunkLimitBytes(long);
public abstract long relocationInFlightPayloadBudgetBytes();
public abstract void setRelocationInFlightPayloadBudgetBytes(long);
public abstract long relocationNodeInFlightPayloadBudgetBytes();
public abstract void setRelocationNodeInFlightPayloadBudgetBytes(long);
public abstract java.time.Duration relocationCutoverWaitTimeout();
public abstract void setRelocationCutoverWaitTimeout(java.time.Duration);
}
public interface systems.zlink.framework.configuration.ZLinkMeshNodeBuilder {
public abstract systems.zlink.framework.configuration.ZLinkMeshNodeBuilder setRoutingIdPrefix(java.lang.String);
public abstract systems.zlink.framework.configuration.ZLinkMeshNodeBuilder setPlacementWeight(int);
public abstract systems.zlink.framework.configuration.ZLinkMeshNodeBuilder setActorCapacity(int);
public abstract systems.zlink.framework.configuration.ZLinkMeshNodeBuilder setSpotCapacity(int);
public abstract systems.zlink.framework.configuration.ZLinkMeshNodeBuilder setActivationConcurrency(int);
public abstract systems.zlink.framework.configuration.ZLinkMeshObjectRoleBuilder objects();
}
public interface systems.zlink.framework.configuration.ZLinkMeshObjectRoleBuilder {
public abstract systems.zlink.framework.configuration.ZLinkMeshObjectClientBuilder client();
public abstract systems.zlink.framework.configuration.ZLinkMeshObjectServerBuilder server();
}
public interface systems.zlink.framework.configuration.ZLinkStreamNodeBuilder {
public abstract systems.zlink.framework.configuration.ZLinkStreamSocketConfig configureSocket();
public abstract systems.zlink.framework.configuration.ZLinkStreamNodeBuilder enableActorDispatch();
}
public interface systems.zlink.framework.configuration.ZLinkStreamSocketConfig {
public abstract long maxMessageSize();
public abstract void setMaxMessageSize(long);
}
Core HWM and application-job-queue configuration is obtained directly
from options.configureInboundDispatch(), which returns
ZLinkInboundDispatchOptions; configureDispatch { ... } remains the
diagnostics DSL and does not forward HWM or job-queue settings.
sessionRelocationSealTimeout() is the same startup-only positive Duration as Java,
defaulting to three seconds. A non-millisecond-representable, zero, negative, or infinite
value is a configuration error before socket bind.
relocationPayloadChunkLimitBytes(), relocationInFlightPayloadBudgetBytes(),
relocationNodeInFlightPayloadBudgetBytes(), and relocationCutoverWaitTimeout() also use
the Java public contract unchanged. The chunk limit is the maximum size in bytes of one
encoded chunk of a relocation payload, defaulting to 256 KiB; setting it above the frame
limit the transport negotiated is a startup configuration error before socket bind. The
in-flight budget caps the sum of relocation chunk bytes concurrently in flight per peer
connection, defaulting to 16 MiB, with 0 meaning not applied. The node in-flight
budget applies the same rule to the node-wide sum and defaults to 0, meaning not
applied. The cutover wait timeout is both the target's wait for cutover and the time
the source keeps its boundary batch copy for retransmission, defaulting to one second.
All four values are startup-only, and negative values are a configuration error before
socket bind.
Kotlin uses Java's ZLinkStreamNodeBuilder.configureSocket() and
ZLinkStreamSocketConfig.setMaxMessageSize(...) unchanged. The default is
64 KiB, and the setting 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 maps to Core -1, so
Framework adds no limit; a negative value is a startup configuration error.
A message over the limit is never partly delivered to the handler. The
server records EMSGSIZE and a diagnostic trace, then closes the connection.
The raw client observes the close without a separate wire error code. The
limit doesn't apply to server-to-client outbound messages, and the setting
isn't added to ClientServer or RouteMesh SS.
The Kotlin binding forwards a positive finite Java Runtime.maxMemory() value to Core as
its runtime memory hint. Core and application-job-queue profiles use the Java public
contract's independent enums and calculations, both defaulting to BALANCED. Pressure thresholds
default to pause 80 and resume 60; pause is an integer in 1..100, resume is an integer in
0..99, and resume must be less than pause. Manual job cap, startup CPU snapshot, and pre-bind
bounds, ordering, and overflow validation also match the Java public contract.
Kotlin Source Signature¶
fun ZLinkFrameworkOptions.useCoroutineHandlers(dispatcher: CoroutineDispatcher)
fun ZLinkFrameworkOptions.useCoroutineHandlers(
scope: CoroutineScope,
dispatcher: CoroutineDispatcher,
)
inline fun ZLinkFrameworkOptions.configureDispatch(
block: ZLinkDispatchOptions.() -> Unit,
): ZLinkDispatchOptions
fun ZLinkFrameworkOptions.configureStreamCompression(
configure: ZLinkStreamCompressionBuilder.() -> Unit,
): ZLinkFrameworkOptions
inline fun <reified TActor, reified TFactory>
ZLinkMeshObjectServerBuilder.actorFactory(
actorType: String,
noinline configure: ZLinkActorFactoryBuilder<TActor>.() -> Unit,
): ZLinkMeshObjectServerBuilder
where TActor : ZLinkActor,
TFactory : ZLinkActorFactory
The factory configure callback has no default. The Actor factory builder has no setting other than relocation behavior selection. Node placement weight is 0..10000, defaulting to 100. An out-of-range value is a configuration error in both startup config and runtime change. It's independent of Channel weight, and the same value is used for runtime update and the descriptor snapshot. RouteMesh Channel Server and ClientServer Server weight also use the same range and default. Weighted selection computes the sum of candidate weight using at least a 64-bit integer.
The automatic RID of a MeshNode and store-backed fanout publisher has
the format prefix-<lowercase-canonical-uuid-v4>. UUID v4 is
represented as a lowercase canonical string in 8-4-4-4-12 digit
groups. Prefix is ASCII [A-Za-z0-9._-] 1..64 characters, and the full
RID is at most 255 UTF-8 bytes. On conflict with an active owner, it
fails immediately with RoutingIdConflict instead of retrying with a
new UUID. A fixed RID is allowed in an automatic discovery topology and on a MeshNode that has an
object role. Implementation and test scenarios sometimes need to name a specific peer, and an
auto-assigned UUID cannot be named. When a node using a fixed RID restarts and collides with the
previous active owner claim, the same rule as an automatic RID applies — it does not retry with a
new value but fails immediately with a conflict, and the restart succeeds once the previous owner
lease expires. There's no slot
count, allocation group, or public allocation provider.
The Object Server's Entry Spot ID has the same-prefix format
<prefix>-entry-<lowercase-canonical-uuid-v4>, using a UUID v4
generated separately from the MeshNode. Java's
ZLinkMeshNodeDescriptor.entrySpotId() provides the mapping for
the same lifecycle. If the global Spot ID conflicts with an active
owner, startup fails immediately with SpotIdConflict instead of
retrying with a new UUID. If a caller-specified User/Instance Spot ID
matches the reserved format, it's rejected as a startup configuration
error before the Store and factory.
Every factory configures the Java builder with a Kotlin receiver
callback. The callback calls exactly one of disableRelocation(),
recreateOnRelocation(), preserveStateWith(...). Omitting it or
calling more than one is a startup configuration error before socket
bind. A Kotlin-only policy value or suspending adapter isn't added. There
is no separate registration API.
The framework runs the receiver callback synchronously exactly once
inside the registration call. Calling the retained builder again after
the callback returns is a configuration error. If the callback throws,
that factory isn't registered and the same exception is propagated to
the caller. If stableTypeLimit(...) is omitted, it shares the node
limit, and an explicit value must be 1..Int.MAX_VALUE. 0 and a
negative value are a configuration error during callback execution.
An Object Server with even one factory that selected
recreateOnRelocation() or preserveStateWith(...), or even one
registered Instance Spot factory, registers exactly one Relocation Store
with the Java root's addRelocationStore(...). Only a same-node
configuration with no Instance Spot factory where every factory
selected disableRelocation() can omit this.
Generated JVM Signature¶
public final class systems.zlink.framework.kotlin.ZLinkCoroutineHandlerOptionsKt {
public static final void useCoroutineHandlers(systems.zlink.framework.configuration.ZLinkFrameworkOptions, kotlinx.coroutines.CoroutineDispatcher);
public static final void useCoroutineHandlers(systems.zlink.framework.configuration.ZLinkFrameworkOptions, kotlinx.coroutines.CoroutineScope, kotlinx.coroutines.CoroutineDispatcher);
}
public final class systems.zlink.framework.kotlin.ZLinkDispatchOptionsExtensionsKt {
public static final systems.zlink.framework.configuration.ZLinkDispatchOptions configureDispatch(systems.zlink.framework.configuration.ZLinkFrameworkOptions, kotlin.jvm.functions.Function1<? super systems.zlink.framework.configuration.ZLinkDispatchOptions, kotlin.Unit>);
}
public final class systems.zlink.framework.kotlin.ZLinkFrameworkExtensionsKt {
public static final <TActor extends systems.zlink.framework.actors.ZLinkActor, TFactory extends systems.zlink.framework.actors.ZLinkActorFactory> systems.zlink.framework.configuration.ZLinkMeshObjectServerBuilder actorFactory(systems.zlink.framework.configuration.ZLinkMeshObjectServerBuilder, java.lang.String, kotlin.jvm.functions.Function1<? super systems.zlink.framework.configuration.ZLinkActorFactoryBuilder<TActor>, kotlin.Unit>);
public static final systems.zlink.framework.configuration.ZLinkFrameworkOptions configureStreamCompression(systems.zlink.framework.configuration.ZLinkFrameworkOptions, kotlin.jvm.functions.Function1<? super systems.zlink.framework.configuration.ZLinkStreamCompressionBuilder, kotlin.Unit>);
}