Configuring WebSocket client
The WebSocketClient is the default client used to connect to the Fluxzero Runtime over WebSocket. It provides full access
to the event store, message gateways, tracking, search, scheduling, and key-value storage subsystems via configurable,
high-throughput sessions.
Creating a WebSocketClient
Section titled “Creating a WebSocketClient”To configure and instantiate a WebSocket-backed client:
WebSocketClient client = WebSocketClient.newInstance( WebSocketClient.ClientConfig.builder() .runtimeBaseUrl("wss://my.flux.host") .name("my-service") .build());
Fluxzero flux = DefaultFluxzero.builder().build(client);val client = WebSocketClient.newInstance( WebSocketClient.ClientConfig.builder() .runtimeBaseUrl("wss://my.flux.host") .name("my-service") .build())
val flux = DefaultFluxzero.builder().build(client)This is the most common setup for production and shared environments. It connects to a remote Fluxzero Runtime via the runtime base URL, which must point to the desired deployment.
The client negotiates compression with the Runtime. See Compatibility & dependencies when upgrading an existing deployment.
Client configuration (ClientConfig)
Section titled “Client configuration (ClientConfig)”The ClientConfig class defines all connection, routing, compression, and tracking parameters. It is fully immutable
and can be created or extended using the toBuilder() pattern.
Key options include:
| Setting | Description | Default |
|---|---|---|
runtimeBaseUrl | Base URL for all subsystems (e.g. wss://my.flux.host) | FLUXZERO_BASE_URL or FLUX_BASE_URL |
name | Name of the application | FLUXZERO_APPLICATION_NAME or legacy alias |
applicationId | Optional app ID | FLUXZERO_APPLICATION_ID or legacy alias |
id | Unique client/process instance ID | FLUXZERO_CLIENT_ID, legacy alias; otherwise task-ID-prefixed UUID or UUID |
supportedCompressionAlgorithms | Preferred and fallback compression algorithms | ZSTD only |
pingDelay / pingTimeout | Heartbeat intervals for WebSocket health | 10s / 15s |
maxConcurrentRuntimeWebSocketMessages | Messages decoded or waiting for completion-dispatcher admission per session | 3 |
maxRetainedRuntimeWebSocketMessages | Total assembling, compressed-pending, decode/admission, and active messages | 128 |
maxRetainedRuntimeWebSocketBytes | Total compressed runtime wire bytes retained per session | 64 MiB |
maxConcurrentRuntimeResultCompletions | Admitted groups and result completions/continuations per client | 8 |
runtimeIngressStallCloseTimeout | Optional close delay after ingress is diagnosed as stalled | Disabled |
aggregateHistoryMaxFetchBytes | Serialized event-payload bytes requested per aggregate-history page | Count-only in compatibility mode; 100 MiB from defaults version 2026.09.10 |
disableMetrics | Whether to suppress all outgoing metrics | false |
typeFilter | Optional message type restriction | null |
FLUXZERO_TASK_ID identifies the hosting platform task or pod; it is not itself a unique process incarnation. When
present, the SDK uses it as the recognizable prefix of a generated client ID and publishes the unchanged value as
authoritative $taskId correlation metadata. The generated client ID remains stable across WebSocket reconnects, but
a newly constructed client receives a new UUID suffix. Set FLUXZERO_CLIENT_ID only when supplying an explicitly
unique client-instance ID; FLUX_CLIENT_ID remains available as a legacy alias.
In compatibility mode, failed WebSocket connections retry every second. Set
fluxzero.websocket.reconnectBackoff.enabled=true, or use fluxzero.defaults.version >= 2026.09.09, to use equal
jitter over capped exponential ceilings of 1, 2, 4, 8, then 16 seconds. A successful connection resets the retry
cycle. Set the dedicated property to false to keep fixed retries on a newer defaults profile. The conventional
environment-variable name is FLUXZERO_WEBSOCKET_RECONNECT_BACKOFF_ENABLED.
Runtime ingress flow control
Section titled “Runtime ingress flow control”The SDK bounds incoming work so slow callbacks do not consume unlimited resources. It limits retained messages and bytes per connection, and separately limits concurrent decoding and result completion. When capacity fills, the connection pauses receiving until work completes.
Keep the defaults unless measurements show a reason to tune them. Larger retained limits can absorb bursts but use more memory; more completion concurrency permits more callbacks to run at once.
| Property | Purpose |
|---|---|
fluxzero.runtime.ingress.maxConcurrency | Concurrent runtime-message decoding per session |
fluxzero.runtime.ingress.maxRetainedMessages | Retained runtime messages per session |
fluxzero.runtime.ingress.maxRetainedBytes | Retained compressed wire bytes per session |
fluxzero.runtime.ingress.maxCompletionConcurrency | Concurrent result completions per client |
fluxzero.runtime.ingress.stallCloseTimeout | Optional delay before closing a stalled connection, such as PT30S |
Use conventional environment-variable names, for example FLUXZERO_RUNTIME_INGRESS_MAX_RETAINED_BYTES.
Explicit builder settings take precedence over properties. The byte limit is a work-admission limit, not a maximum
response size; one oversized response can still proceed alone.
Diagnosing stalled connections
Section titled “Diagnosing stalled connections”Set fluxzero.websocket.transportMetrics.enabled=true
(FLUXZERO_WEBSOCKET_TRANSPORT_METRICS_ENABLED) for transport diagnostics. A stalled connection has retained work
without functional progress; an idle connection is not stalled. The optional stall-close timeout is disabled by
default. Consider it when a silent connection failure must be detected even while local backpressure pauses receiving.
Controlled application shutdown disables ingress-stall/recovery diagnostics and stall-triggered connection closure
before shutdown callbacks and consumers drain. Connections remain available for pending results, position updates
and shutdown publications. This applies to namespace clients as well. If you manage a client lifecycle directly,
call Client.prepareShutdown() before draining your own callbacks, then Client.shutDown() to release resources.
The same lifecycle applies in Java and Kotlin.
Tracker cancellation waits at most one second across the parallel trackers in a registration. It does not interrupt an active handler or acknowledge unfinished work. A blocked worker runs interceptor cleanup after it eventually exits; custom cleanup must remain bounded. Component shutdown budgets can accumulate, so this is not a global application-shutdown deadline.
For defaults, valid ranges and the exact admission and shutdown contracts, see WebSocketClient.ClientConfig .
Packed Model substeps
Section titled “Packed Model substeps”Supported wire representations are negotiated automatically with the Runtime. Applications do not configure packed Model substeps. See Compatibility & dependencies for upgrade order and older peers.
Subsystem sessions
Section titled “Subsystem sessions”Flux opens multiple WebSocket sessions to handle parallel workloads. You can tune the number of sessions per subsystem:
ClientConfig config = ClientConfig.builder() .eventSourcingSessions(2) .searchSessions(3) .gatewaySessions(Map.of(COMMAND, 2, EVENT, 1)) .build();val config = ClientConfig.builder() .eventSourcingSessions(2) .searchSessions(3) .gatewaySessions(mapOf(COMMAND to 2, EVENT to 1)) .build()Each session can multiplex multiple consumers or producers under the hood. Use more sessions to improve parallelism and isolation across critical workloads.
Tracking configuration
Section titled “Tracking configuration”Tracking clients can use local caches to optimize polling performance when many consumers are tracking the same topic or message type.
ClientConfig config = ClientConfig.builder() .trackingConfigs(Map.of( EVENT, TrackingClientConfig.builder() .sessions(2) .cacheSize(1000) .build())) .build();val config = ClientConfig.builder() .trackingConfigs( mapOf( EVENT to TrackingClientConfig.builder() .sessions(2) .cacheSize(1000) .build() ) ) .build()The cacheSize determines how many messages are buffered in-memory per topic. This helps reduce round-trips to the
Runtime and can significantly boost performance in high-fanout projections or handlers.
Integration with FluxzeroBuilder
Section titled “Integration with FluxzeroBuilder”Once created, the client is passed into the builder:
Fluxzero flux = DefaultFluxzero.builder() .makeApplicationInstance(true) .build(webSocketClient);val flux = DefaultFluxzero.builder() .makeApplicationInstance(true) .build(webSocketClient)Local alternative
Section titled “Local alternative”For testing or lightweight local development, use the in-memory LocalClient instead:
Fluxzero flux = DefaultFluxzero.builder().build(LocalClient.newInstance());val flux = DefaultFluxzero.builder().build(LocalClient.newInstance())This simulates the entire platform in-memory without external dependencies.
© 2026 Fluxzero