Rust SDK worker refusals
Workers answer a pushed request with PushClient::reply or refuse it with
PushClient::refuse(correlation_id, code, words). PushWriter offers both
methods on the same connection. A refusal accepts the closed codes busy,
invalid, unavailable, and internal.
The wire-configured words limit is 1024 UTF-8 bytes, preserving a useful
explanation while bounding storage and decoding. Both worker APIs validate the
code and byte length before locking or writing the socket. Invalid data returns
SdkError::Protocol with the bound or fault name and no application data.
Worker identities must fit in 993 UTF-8 bytes so a malformed refusal can name
the full station within the same 1024-byte explanation bound. Registration
rejects a longer identity with worker_station_too_long; names are never
truncated.
let request = worker.recv?;
if let Frame = request
A Rust conversation caller receives
SdkError::WorkerRefused { code, words }. code is the worker code without the
worker_ prefix, and words is exact. Display returns those words; Debug
records only the code and the words' byte count. Route admission errors remain
SdkError::Conversation. Classification uses the conversation's numeric reason
code, never a prefix in its message.
The existing host-side server push awaiter returns the stable worker_<code>
alone through its legacy PushReplyRefused error. Routed calls retain the
validated refusal separately so its words reach only the authorised caller.
The wire fixture pins every code, a maximal
UTF-8 words case, complete worker and caller frames, and an unchanged opaque
reply. Its 0x0401–0x0404 conversation reasons map to worker_busy,
worker_invalid, worker_unavailable, and worker_internal. The server logs
malformed or reserved-flag replies by fault name without their bytes. A refusal
settles its slot once; duplicate replies are discarded.
Verify the SDK's live TCP pin on a socket-capable host with
cargo nextest run -p liminal-sdk --features embedded --lib refusal.
What a client links
std, the default, gives the native TCP and WebSocket clients, and wss adds
wss:// to a TLS-terminating proxy. Neither the default client nor std nor
wss links a server crate. The wire codec comes from liminal-bus-protocol
(AGPL-3.0-only, as liminal-rs), which depends only on serde_json and
thiserror, so a client compiles and links no liminal-rs, haematite, beamr
or Cranelift.
embedded links liminal-server, the whole server, in process, under its own
licence.
A reply names its request as its parent through DeliveredId::reply_parent.
Take DeliveredId from the SDK, as liminal_sdk::DeliveredId. Move
liminal-sdk and any liminal-rs you depend on together: liminal-rs 0.16.24
or older beside this SDK holds a second DeliveredId type.