Guide Home | Previous: E2E Testing | Next: Where ZLink Fits
16. Options — Configuration List And Defaults¶
The documents that own this chapter's contract — Topology public interfaces and Host configuration interfaces define the exact signatures and value ranges. This chapter helps you list that surface out and judge when to change it.
The earlier chapters explain features and cover only the settings needed at that point. This chapter is one place that collects every setting you can specify.
Most of them work fine unchanged. That's why every table below lists the default — check the relevant row when a reason to change it comes up, and use the default until then.
1. Where A Setting Applies¶
The same setting has a different scope depending on where you specify it.
%%{init: {'flowchart': {'nodeSpacing': 32, 'rankSpacing': 40, 'padding': 8, 'wrappingWidth': 180}, 'themeVariables': {'fontSize': '18px', 'edgeLabelBackground':'transparent'}}}%%
flowchart TD
R["① Root options<br/>process-wide defaults"]:::root
subgraph BUILD["② Builder — applies to one only"]
direction LR
M["MeshNode"]:::unit
F["fanout channel"]:::unit
S["STREAM node"]:::unit
end
RT["③ Runtime option<br/>a value changed while running"]:::rt
R --> BUILD
BUILD -.->|"after app.Run()"| RT
classDef root fill:#e3f2fd,stroke:#1565c0,color:#0d47a1
classDef unit fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px,color:#1b5e20
classDef rt fill:#fff3e0,stroke:#e65100,color:#bf360c
style BUILD fill:#ffffff,stroke:#1565c0,stroke-width:2px,color:#000000
builder.Services.AddZLinkFramework(options =>
{
options.Codecs.Use(ZLinkProtobufCodec.Default); // ① Root — applies to every payload in this process.
var mesh = options.AddRouteMesh("play") // ② Builder — applies only to this one node.
.Listen(node.MeshEndpoint)
.SetRoutingIdPrefix("play")
.SetSpotLimit(2_000);
mesh.Channel("room").Server();
});
// ③ Runtime — changed while running.
app.MapPost("/admin/drain", (IZLinkRouteMeshRuntimeOptions runtime) =>
{
runtime.Channel("room").Weight = 0; // Only stops accepting new requests. The connection is kept.
return Results.Ok();
});
| Spot | Scope | When it can change |
|---|---|---|
Root options |
Process-wide default | Only before app.Run() |
| Builder | That one node/channel/STREAM node | Only before app.Run() |
| Runtime option | Some values already running | While running (What Can Change While Running) |
There's no surface to call a builder again after app.Run(). A bad combination isn't
deferred to the first call — it's blocked as an exception at host startup.
2. Root Options¶
Values applied across the whole process.
| Setting | What it sets | Default | When to change it |
|---|---|---|---|
DefaultRequestTimeout |
The ceiling a request waits for a response | 30s | The service's response is slower than that, or you want to fail faster |
DefaultSocketSendTimeout |
The ceiling to wait when there's no slot to send into (backpressure) | 1s | To tolerate congestion longer, or to fail faster |
Codecs.Use(...) |
How the payload is turned into bytes | The built-in default codec | Fixing on Protobuf/MessagePack, or using your own serializer |
AddHandlersFromAssemblyOf<T>() |
The assembly to find handler types in | Not searched | Letting handlers be discovered automatically |
DisableImplicitHandlerAutoRegistration() |
Turns off auto-registration of discovered handlers | On | Controlling which handler opens on which channel purely through registration code |
UseFilter<T>() |
Common processing to put in front of handlers | None | Gathering logging/validation/authorization in one place |
ConfigureMetadata() |
The metadata keys allowed to pass between a client connection and an actor | No key allowed | Something like auth info needs to pass from the connection to the actor |
ConfigureNetwork() |
The default BindHost/AdvertiseHost for every endpoint |
Unspecified | The bind address and advertised address need to differ in a container/Kubernetes |
ConfigureDispatch() |
Unhandled dispatch and diagnostics | Diagnostics use Errors |
Tuning dispatch policy or diagnostics |
ConfigureInboundDispatch() |
Core HWM and the application job queue | Both profiles use Balanced |
Tuning the Core byte budget or the queued-job limit |
ApplicationVersion |
This process's application version | 0 |
Picking a relocation target by version during a zero-downtime deploy |
MaintenanceWave |
The maintenance group name this process belongs to | None | Grouping nodes to maintain/replace in sequence |
Worker |
The thread pool heavy work is handed off to | Max processor count × 2 (min 2) · 30s idle · 1024 queue |
Handing off a lot of slow computation/I/O to a worker |
- Choosing a codec and registering your own serializer: 05-channel-messaging
- The difference between discovering and exposing a handler: 05-channel-messaging
- The scope a filter applies to: 05-channel-messaging
- Worker calls: 06-spot
- The deployment flow that uses version/maintenance groups: 12-operations
AddLocationStore(...) and AddRelocationStore(...) are also registered at the root. The
auto-connect that finds a peer by logical name is covered by
10-location; the store used when moving state to another node is
covered by 07-actor-spot.
Metadata only lets through a key you've opened. Unless you specify per-direction allowed keys with
AllowSessionToActorandAllowActorToSession, no value passes at all. Since it fails silently — the value just disappears with no error — don't forget this setting in a setup that passes authentication results from a connection to an actor.
3. MeshNode Options¶
A MeshNode is the basic unit of a connection
between servers, and one process creates one per mesh. The following are specified on the
builder AddRouteMesh(name) returns, and apply only to that one node.
| Setting | What it sets | Default | When to change it |
|---|---|---|---|
Listen(endpoint) · Listen(port) |
This node's own endpoint for other nodes to connect to | None | Always needed. Leave the port 0 to get one automatically |
SetBindHost · SetAdvertiseHost |
A bind/advertise address just for this node | The root ConfigureNetwork() value |
Each node needs a different address rule |
SetRoutingIdPrefix(...) |
The prefix of an auto-issued identifier | None | The common case. Gets a new identifier on every restart, so it never mixes with the previous process |
SetRoutingId(...) |
A fixed identifier for this node | None | Only when the same identifier must carry over even after replacing the process |
SetPlacementWeight(int) |
The ratio at which a new Spot/actor is placed on this node | 100 | Mixing nodes of different specs, or halting new placement |
SetSpotLimit(int) |
The ceiling on Spots this node can hold at once | Unlimited | Enforcing a memory limit by Spot count |
SetActorLimit(int) |
The ceiling on this node's actor count | Unlimited | Setting a per-node cap on connected-user count |
SetActivationConcurrency(int) |
The number of Spot/actor activations that can proceed concurrently | 128 | Limiting store load when activations pile up |
SetDefaultRequestTimeout(...) |
The default wait ceiling for a request going out from this mesh | The root value (30s) | Only this mesh's response is slow or fast |
PeerConnections.Connect(endpoint) |
A peer endpoint to connect to manually | None | A setup that doesn't use auto-connect |
The registrations done in Objects().Server() and Channel(name).Server() (stable type,
relocation policy, channel weight) are covered by 06-spot and
05-channel-messaging. Manual connection is covered by
05-channel-messaging.
3.1 Backpressure — Send-Wait Behavior¶
A sent message leaves through a per-peer send queue, and once that queue hits its ceiling,
the sender waits. At this point, it waits up to DefaultSocketSendTimeout (1s by
default) for a slot to open, submits once the slot opens, and if it never opens, ends in a
DeadlineExceeded exception. It's never auto-resent, so whether to retry is up to the
application.
await client.SendToChannel("profile", command).Async(ct);
// This await finishing means only "my runtime accepted the submission."
// It doesn't mean the peer received it or the handler finished.
Why the peer's delay becomes this side's wait, and when the ceiling locks and unlocks, is covered by 04-backpressure. This section and the next only cover the options that set values within that behavior. Flow control itself is owned by Core, and the exact contract is covered by the core guide's socket option.
Logical Multicast is judged separately per target. Failing to submit to one target doesn't roll back a target already accepted, and it doesn't return a per-target failure as the publish result either.
3.2 Options That Set The Backpressure Ceiling¶
ConfigureRouterSocket() sets the ceiling for the socket this node uses; ConfigureSpotPublisher()
sets the manual ceiling for the publish socket Spots use to exchange events. For an unset
direction, Core calculates the HWM from the context budget and physical-queue census. The
framework does not calculate a separate connection-count bucket table
(04-backpressure §4.1).
| Setting | What it sets | Raising it | Lowering it |
|---|---|---|---|
SendHighWaterMark |
Bytes this node can hold, per peer, to send. 0 means unlimited |
Absorbs more of a momentary burst | The sender waits sooner, surfacing congestion faster |
ReceiveHighWaterMark |
Bytes this node can hold, per peer, after receiving. 0 means unlimited |
Tolerates more processing delay | This node fails to pick messages up sooner, delaying the peer's send first |
MailboxMessageBudget · MailboxByteBudget |
The message count and bytes one execution unit like a Spot/Actor can hold | A slow execution unit tolerates more of a burst | Surfaces a delayed execution unit sooner |
ReceiveTimeout · SendTimeout |
The socket-level wait ceiling | — | The default behavior is enough in most cases |
Linger (publish socket) |
How long to wait for a remaining message when closing | Doesn't drop the last publish on shutdown | The default is 0, so it closes immediately |
The two manual HWMs differ only in direction and apply to that socket-direction physical queue. They are not the Core-context-wide byte budget or the application job queue's job limit.
Raising the high-water mark isn't the default response. A larger ceiling absorbs
congestion into memory, which makes DeadlineExceeded show up later — and that delays
learning the cause just as much. Raise it only for a short, clear burst window; if
processing delay keeps happening, check the processing side (receiving node count, handler
execution time) instead of the ceiling. Conversely, to fail fast and switch to a different
path, lower the ceiling and shrink DefaultSocketSendTimeout.
Leaving MaxMessageSize unlimited means one message can exceed the ceiling by any amount,
making it impossible to compute the worst-case memory a queue can occupy. If you're planning
process memory based on the byte ceiling, specify a finite value.
3.3 Core HWM And The Application Job Queue¶
These are values on IZLinkInboundDispatchOptions, returned by ConfigureInboundDispatch().
| Setting | What it sets | Default |
|---|---|---|
CoreHwmMemoryLimitBytes |
Memory-limit hint forwarded for Core budget calculation | null |
CoreHwmBudgetBytes |
Manual Core budget that takes precedence over the profile | null (Auto) |
CoreHwmProfile |
Core Auto-budget profile | Balanced |
ApplicationJobQueueProfile |
Queued-job Auto profile | Balanced |
MaxQueuedApplicationJobs |
Exact manual queued-job limit | null (Auto) |
The memory limit and Core budget must be positive. The manual queued-job limit is
1..2,147,483,647; 0 is a startup configuration error, not unlimited. The two profiles
use the same labels but are independent enums and calculations. See
4. Backpressure and Common Perf §23
for saturation behavior and production measurement.
4. Error Handling And Diagnostics¶
ConfigureDispatch() sets the behavior when an unregistered packet arrives and how
much diagnostics is recorded.
var dispatch = options.ConfigureDispatch();
dispatch.Unhandled.Request = ZLinkUnhandledDispatchAction.ReplyError; // The sender receives it as an error.
dispatch.Unhandled.Publish = ZLinkUnhandledDispatchAction.Drop; // Drops an event no one's interested in.
dispatch.Diagnostics
.SetLevel(ZLinkDiagnosticsLevel.Normal)
.IncludeMessageSizes(false);
Unhandled is set separately for the three directions request/send/publish.
| Value | Behavior | When to pick it |
|---|---|---|
ReplyError |
Sends an error response to the sender | The default for request. The caller needs to know right away |
LogAndDrop |
Logs it and drops it | send/publish, when you want a record of the cause without breaking the flow |
Drop |
Drops it silently | An event the subscriber isn't interested in mixes in normally |
Throw |
Throws an exception | Surfacing a contract mismatch immediately during development/testing |
Diagnostics sets the following.
| Setting | What it sets | When to change it |
|---|---|---|
SetLevel(...) |
The record level, one of Off · Errors · Normal · Detailed |
Normal normally; Detailed only when tracing a cause |
SetSampleRate(double) |
The fraction to record | When traffic is heavy enough that recording everything is a burden |
IncludeMessageSizes(bool) |
Whether to record message size | Need to check payload size |
How to read the record left here is covered by 11-monitoring.
5. Location Options¶
ConfigureLocations() sets the interval and validity period for refreshing location
information. Registration and relocation
behavior are covered by 10-location.
| Setting | What it sets | Default | When to change it |
|---|---|---|---|
OwnerLeaseRenewInterval |
The interval to renew your own ownership | 5s | Lengthen to reduce store write load |
OwnerLeaseTtl |
The time before an ownership with stalled renewal expires | 15s | Shorten to detect failure faster; lengthen to tolerate a temporary delay |
OwnerLeaseRenewTimeout |
The ceiling for one renewal attempt | 3s | When the store's response is slow |
OwnerLeaseFencingMargin |
The margin to voluntarily give up authority ahead of expiry | 5s | Narrowing the moment two nodes could own the same target |
PollingInterval |
The interval to re-read the store when there's no change notification | 1s | Balancing store load against how fast changes are reflected |
StoreFailureGrace |
How long a store outage is tolerated | 30s | Once this passes, no new connection starts. Existing connections are kept |
RouteCacheMaxAge |
How long a looked-up location is reused | 15s | 0 means no caching. Shorten if moves are frequent |
MessageFollowDuration |
How long the previous owner node forwards messages to the new owner | 30s | 0 means it doesn't forward |
6. STREAM Options¶
STREAM is a connection-oriented channel to an external client like mobile or a game. Specify the following on the node that receives that connection. Usage is covered by 09-stream.
| Setting | What it sets | Default | When to change it |
|---|---|---|---|
AddStreamNode(name).Bind(...) |
The endpoint a client connects to | None | Always needed |
SetBindHost · SetAdvertiseHost |
The bind/advertise address | The root ConfigureNetwork() value |
Container deployment |
SetTlsServer(cert, key, requireClientCertificate) |
The server certificate and whether a client certificate is required | Off | Exposing this directly to the outside |
EnableActorDispatch() |
Hands an incoming packet to the bound actor | Off | A setup that ties the connection to an actor (08-actor-session) |
AddSession<T>() |
The session implementation that handles connection lifetime | None | Handling connect/authenticate/disconnect directly |
ConfigureStreamCompression() |
Compression for payload exchanged with the client | LZ4 | Turning it off with Disable(), or swapping in your own codec |
7. What Can Change While Running¶
The rest of the settings are fixed at startup. The settings that can change while running are:
| Setting | Injected as | What it changes |
|---|---|---|
| Channel weight | IZLinkRouteMeshRuntimeOptions |
Channel(name).Weight — the ratio at which this node accepts new requests. 0 keeps the connection but stops accepting new requests |
| Placement weight | IZLinkRouteMeshRuntimeOptions |
Mesh(name).PlacementWeight — the ratio at which a new Spot/actor is placed on this node |
| Diagnostics level | IZLinkDiagnosticsRuntime |
Level — raise to Detailed only while tracing a cause, then revert |
A weight value ranges 0..10000, with a default of 100. The operational flow is covered by
05-channel-messaging and
12-operations.
8. What You Must Set¶
There aren't many settings without a default that you have to specify yourself.
| Required setting | If you skip it |
|---|---|
A MeshNode's Listen(...) |
Exception at host startup |
| At least one channel or object role on a MeshNode | Exception at host startup |
| Exactly one relocation policy on a Spot/actor factory | Exception at host startup |
A STREAM node's Bind(...) |
Exception at host startup |
AddLocationStore(...) if using auto-connect, PeerConnections.Connect(...) if not |
Can't find a peer to connect to |
| The metadata key to pass between a connection and an actor | The value just fails to pass, with no error |
Everything else starts from its default.
9. Common Problems¶
- A setting changed, but it didn't take effect → most options are fixed before
app.Run(). What can change while running is listed in §7. - Metadata isn't reaching the actor → check whether
ConfigureMetadata()allowed that key for the right direction. An unallowed key disappears with no error. - Another node can't connect in a container → the bind address may be getting used as the
advertised address as-is. Use
ConfigureNetwork()or the node'sSetAdvertiseHostto specify the address a peer should connect to. sendends inDeadlineExceeded→ it waited for a send slot and hit the ceiling (backpressure). Check the receiving side's processing speed first, and if it's a short burst, raiseSendHighWaterMarkorDefaultSocketSendTimeout.- The store slows down when activations pile up → lower
SetActivationConcurrency(default 128) to reduce concurrent activations.
10. Related Documents¶
- The interface index for the registration surface:
13-interface-catalog §2 Topology Registration
— the verification class
BuilderContracts - The exact signatures and value ranges: Topology public interfaces · Host configuration interfaces
- Registration points and layering: 01-overview
- Runtime observation and operations: 11-monitoring · 12-operations