pub struct LiminalConnectionServices { /* private fields */ }Expand description
Default adapter from server wire frames to liminal channel/conversation APIs.
Implementations§
Source§impl LiminalConnectionServices
impl LiminalConnectionServices
Sourcepub fn from_config(config: &ServerConfig) -> Result<Self, ServerError>
pub fn from_config(config: &ServerConfig) -> Result<Self, ServerError>
Builds library-backed services from validated server configuration.
Durable-mode channels are backed by a shared haematite event store so their publishes are persisted and survive the graceful-shutdown flush; ephemeral channels carry no store.
Full-only: a config selecting the worker-front-door profile is rejected at
entry (before any store is built), so this constructor can never build full
services for a profile that forbids them. Profile-aware callers go through
build_connection_services instead.
§Errors
Returns ServerError when the config selects a non-full profile or a
configured channel cannot be initialized.
Sourcepub fn from_config_with_store(
config: &ServerConfig,
durable_store: Arc<dyn DurableStore>,
) -> Result<Self, ServerError>
pub fn from_config_with_store( config: &ServerConfig, durable_store: Arc<dyn DurableStore>, ) -> Result<Self, ServerError>
Builds services over a caller-provided durable store.
Used by tests that need to inspect persisted state through the same store handle the durable channels write to.
Full-only: rejects a worker-front-door profile at entry, exactly like
Self::from_config.
§Errors
Returns ServerError when the config selects a non-full profile or a
configured channel cannot be initialized.
Sourcepub fn empty() -> Result<Self, ServerError>
pub fn empty() -> Result<Self, ServerError>
Builds services with no configured channels.
§Errors
Returns ServerError when the conversation supervisor scheduler cannot start.
Sourcepub const fn channel_cluster(&self) -> &ChannelCluster
pub const fn channel_cluster(&self) -> &ChannelCluster
The shared channel supervisor + cluster resolver backing this service.
The server runtime uses this to attach the cluster to the channel supervisor’s clustered scheduler (SRV-005).
Sourcepub fn durable_store(&self) -> Arc<dyn DurableStore> ⓘ
pub fn durable_store(&self) -> Arc<dyn DurableStore> ⓘ
Returns the shared durable store backing this service’s durable channels.
Sourcepub fn unloadable_conversation_record(
&self,
) -> Option<UnloadableConversationRecord>
pub fn unloadable_conversation_record( &self, ) -> Option<UnloadableConversationRecord>
The production participant handler’s refused-load record, when a participant is configured.
The server’s startup path publishes this onto the health endpoint so
GET /unloadable-conversations answers from the same record the
handler writes. None means no participant is configured at all, which
the surface reports as a distinct state from “nothing was refused”.
Sourcepub fn conversation_supervisor(&self) -> Arc<ConversationSupervisor> ⓘ
pub fn conversation_supervisor(&self) -> Arc<ConversationSupervisor> ⓘ
Returns the conversation supervisor backing supervised conversations.
Tests use this to reach the underlying beamr scheduler so they can spawn or terminate participant processes and exercise crash detection.
Sourcepub fn register_responder(
&self,
subject: impl Into<String>,
behaviour: Arc<dyn ParticipantBehaviour>,
) -> Result<Option<Arc<dyn ParticipantBehaviour>>, ServerError>
pub fn register_responder( &self, subject: impl Into<String>, behaviour: Arc<dyn ParticipantBehaviour>, ) -> Result<Option<Arc<dyn ParticipantBehaviour>>, ServerError>
Registers a custom conversation responder for a routing subject.
When a conversation is later opened with this exact subject, its
participant runs behaviour instead of the built-in EchoBehaviour.
The responder is spawned and supervised identically to the echo
participant — a real linked beamr process with the same crash-detection
semantics — so this exposes the responder seam without changing how
participants run. Registering a subject that already has a responder
replaces it; the previous behaviour is returned.
This is the liminal-side seam aion #13 plugs a remote worker into: it registers a responder that forwards each request to the worker and routes the worker’s reply back through the conversation. Subjects with no registration keep echoing, so existing callers are unaffected.
§Errors
Returns ServerError when the responder registry lock is poisoned.
Sourcepub fn unregister_responder(
&self,
subject: &str,
) -> Result<Option<Arc<dyn ParticipantBehaviour>>, ServerError>
pub fn unregister_responder( &self, subject: &str, ) -> Result<Option<Arc<dyn ParticipantBehaviour>>, ServerError>
Removes the custom responder registered for subject, if any.
After removal the subject reverts to the built-in EchoBehaviour on the
next Self::open_conversation. Returns the removed behaviour when one
was registered.
§Errors
Returns ServerError when the responder registry lock is poisoned.
Source§impl LiminalConnectionServices
The runtime channel-registration surface.
impl LiminalConnectionServices
The runtime channel-registration surface.
Inherent methods, not trait methods, and deliberately so: this is
authority-moving vocabulary that belongs to the ONE adapter owning a channel
roster. Putting register/quiesce on the public ConnectionServices
trait would break every external implementor and would hand
register/quiesce words to a profile that serves no channels at all.
The same seam as the existing runtime-mutation API on this type
(register_responder/unregister_responder): &self, interior mutability,
typed Result.
Sourcepub fn register_channel(
&self,
spec: &ChannelRegistration,
) -> Result<Registered, ChannelRegistryError>
pub fn register_channel( &self, spec: &ChannelRegistration, ) -> Result<Registered, ChannelRegistryError>
Registers spec on the live roster.
Idempotent when an entry of that name already has an IDENTICAL
configuration — mode, protocol schema id, and schema document, all three
— and refuses typed, naming the first differing field, otherwise. An
identical registration against a boot-configured entry answers
Registered::AlreadyIdentical and leaves its origin alone: flipping it
would make the entry lie about its restart fate and would move it into
the counted population without a channel having been created.
The cap is consulted first, in two steps with different reach. An absent
limits.max_channels refuses EVERY call, identical or not, before the
roster is read at all: a deployment that has declared no bound has not
said what it admits, and unbounded-by-default is not a bound. A REACHED
cap refuses only a call that would create an entry — it gates the insert,
which is the population it bounds. An identical re-registration inserts
nothing and so is answered AlreadyIdentical even at a full roster;
refusing it would break idempotency at exactly the boundary a projector
re-projecting its record crosses.
§Errors
Returns ChannelRegistryError when no cap is configured, the cap is
reached, the name exists with a different configuration, the schema bytes
do not parse or compile, durable initialization over the shared store
fails, or the roster lock is poisoned.
Sourcepub fn quiesce_channel(
&self,
name: &str,
reason: impl Into<String>,
) -> Result<(), ChannelRegistryError>
pub fn quiesce_channel( &self, name: &str, reason: impl Into<String>, ) -> Result<(), ChannelRegistryError>
Moves name from active to quiesced with a named reason. ONE-WAY.
New publishes and new subscribes are refused afterwards, carrying the reason. Existing subscriptions are UNTOUCHED: nothing revokes a subscription handle, the actor’s subscriber list is not walked, no EXIT is sent, and the channel actor keeps running. Quiesce is a roster-level admission decision, not an actor command.
Re-quiescing under the IDENTICAL reason is Ok(()); a DIFFERENT reason
refuses, carrying the reason already on record.
The return does NOT mean “no new subscriber can appear”. A subscribe that has already passed admission completes and gets its stream — the linearisation point is the admission read, not the subscribe’s completion. A consumer that needs “nobody is attached” must observe attachment directly.
§Errors
Returns ChannelRegistryError when the name is not registered, is
already quiesced under a different reason, or the roster lock is
poisoned.
Sourcepub fn channel_status(
&self,
name: &str,
) -> Result<ChannelStatus, ChannelRegistryError>
pub fn channel_status( &self, name: &str, ) -> Result<ChannelStatus, ChannelRegistryError>
Cheap typed probe: one roster read plus one atomic load.
Touches no actor and therefore CANNOT spawn one. Every handle accessor that could answer a question about a channel’s activity routes through the lazy-spawn path, so a probe built on one would materialise the actor of the idle channel it was asked about — turning a read into a side effect. This reads the roster entry’s own recorded fields and nothing else.
§Errors
Returns ChannelRegistryError::RosterUnavailable only.
Sourcepub fn registered_channels(
&self,
) -> Result<Vec<ChannelDescriptor>, ChannelRegistryError>
pub fn registered_channels( &self, ) -> Result<Vec<ChannelDescriptor>, ChannelRegistryError>
The whole roster: one minimal descriptor per entry, sorted by name.
The census companion to Self::channel_status. A by-name probe answers
about a name the caller already suspects; only an enumeration can reveal
a name the caller does not know to ask about, and a verification sweep
with no population denominator is an instrument shape this estate
forbids. Touches no actor, under the same constraint as the probe.
§Errors
Returns ChannelRegistryError::RosterUnavailable only.
Trait Implementations§
Source§impl ConnectionServices for LiminalConnectionServices
impl ConnectionServices for LiminalConnectionServices
Source§fn admit_channel(
&self,
_operation: ChannelOperation,
channel: &str,
) -> Result<(), ChannelAccessError>
fn admit_channel( &self, _operation: ChannelOperation, channel: &str, ) -> Result<(), ChannelAccessError>
The roster’s admission decision, exposed across the trait boundary as the permission alone.
Two methods share the name admit_channel on this type: this trait
method, and the private inherent funnel it delegates to. They are the
same decision at two different boundaries — the funnel returns the ENTRY
the decision was made on, because its in-crate callers go on to publish
or subscribe through it, and this one returns (), because a caller
outside the crate is asking whether it MAY, not for the thing itself.
Handing the entry out here would make [ConfiguredChannel] public
surface and hand a frame-level caller a channel handle it has no business
holding. Rust resolves an inherent method ahead of a trait method of the
same name, so the funnel’s existing callers — and the Self:: call below
— reach the funnel, not this method; the trait form is reached only
through a dyn ConnectionServices, which is exactly the caller it exists
for. an_admitted_operation_the_service_then_refuses_stays_undifferentiated
is the instrument that would catch this delegation turning into a
recursion.
operation is unused in v1 and the parameter is still right: absence
refuses both operations, and quiesce refuses new publishes and new
subscribes alike, so the two answers are equal today and not equal by
definition. A signature that could not see what it was deciding about
would have to break the day they part.