pub struct ChannelHandle { /* private fields */ }Expand description
Cloneable handle for interacting with a channel actor process.
Implementations§
Source§impl ChannelHandle
impl ChannelHandle
Sourcepub fn publish_with_idempotency_key<Payload: AsRef<[u8]>>(
&self,
payload: Payload,
publisher_id: PublisherId,
causal_context: Option<CausalContext>,
idempotency_key: &str,
) -> Result<ChannelDelivery, LiminalError>
pub fn publish_with_idempotency_key<Payload: AsRef<[u8]>>( &self, payload: Payload, publisher_id: PublisherId, causal_context: Option<CausalContext>, idempotency_key: &str, ) -> Result<ChannelDelivery, LiminalError>
Publishes as ChannelHandle::publish_with_delivery does, and stores
the producer’s idempotency key in the persisted row so the row can be
found by its key.
§Errors
Returns the errors of ChannelHandle::publish_with_delivery. A
durable append whose outcome is not known is
LiminalError::PublishUnresolved, never a definite failure.
Sourcepub fn durable_positions(&self) -> Result<Vec<u64>, LiminalError>
pub fn durable_positions(&self) -> Result<Vec<u64>, LiminalError>
Where each partition of the durable channel stands: the sequence its next row takes. A claim records these before its publish appends, so a later lookup of its key starts here.
§Errors
Returns LiminalError::PublishFailed when the channel is not durable
or its state is unavailable.
Sourcepub fn resolve_idempotency_key(
&self,
idempotency_key: &str,
from: &[u64],
) -> Result<AppendResolution, LiminalError>
pub fn resolve_idempotency_key( &self, idempotency_key: &str, from: &[u64], ) -> Result<AppendResolution, LiminalError>
Resolves the channel’s pending append, fanning out a committed row,
then looks the row carrying idempotency_key up in the channel’s
stream from the positions in from, page by page, with the append
lock released. Writes no row.
§Errors
Returns LiminalError::PublishUnresolved when the pending append
cannot be read back, and LiminalError::ResolutionUnreadable naming
the channel and the key when the stream cannot be read.
Source§impl ChannelHandle
impl ChannelHandle
Sourcepub fn install_publication_identity(
&self,
source: Arc<dyn PublicationIdentity>,
) -> Result<(), LiminalError>
pub fn install_publication_identity( &self, source: Arc<dyn PublicationIdentity>, ) -> Result<(), LiminalError>
Installs a transport allocator before publishing or exposing this handle.
§Errors
An allocator was already installed on this shared channel handle.
Sourcepub fn new(config: ChannelConfig) -> Self
pub fn new(config: ChannelConfig) -> Self
Creates an ephemeral handle backed by a real supervised channel actor on the shared default supervisor.
The actor process is spawned lazily on first use; a scheduler failure is
surfaced as a LiminalError from the first operation, not a panic.
Sourcepub fn with_supervisor(
config: ChannelConfig,
supervisor: ChannelSupervisor,
) -> Self
pub fn with_supervisor( config: ChannelConfig, supervisor: ChannelSupervisor, ) -> Self
Creates an ephemeral handle bound to an explicit supervisor (isolation
for the registry and tests).
Sourcepub fn new_durable(
config: ChannelConfig,
store: Arc<dyn DurableStore>,
) -> Result<Self, LiminalError>
pub fn new_durable( config: ChannelConfig, store: Arc<dyn DurableStore>, ) -> Result<Self, LiminalError>
Creates a durable handle that persists every accepted publish to store
before fanning it out to subscribers.
Construction reads the store: every partition’s next-sequence counter is recovered from the existing stream head, so a handle rebuilt over a previously used store resumes appending where the log left off instead of conflicting at sequence zero. A fresh store recovers to zero, which is identical to cold start. This makes construction O(stream length) in store reads and adds store read errors to the failure modes below.
§Errors
Returns LiminalError::PublishFailed when the durable channel cannot be
initialized over store, including when recovering the per-partition
sequence counters from the store fails.
Sourcepub fn new_durable_with_supervisor(
config: ChannelConfig,
store: Arc<dyn DurableStore>,
supervisor: ChannelSupervisor,
) -> Result<Self, LiminalError>
pub fn new_durable_with_supervisor( config: ChannelConfig, store: Arc<dyn DurableStore>, supervisor: ChannelSupervisor, ) -> Result<Self, LiminalError>
Creates a durable handle bound to an explicit supervisor.
Used by the standalone server so every channel — durable or ephemeral — shares ONE (optionally clustered) supervisor and thus one scheduler, which is the precondition for cross-node delivery (SRV-005): a subscriber pid joined to a channel’s distributed process group must live on the same scheduler that owns the distribution links.
Like Self::new_durable, construction recovers each partition’s
next-sequence counter from the store, so restarting over an existing
persistence path resumes the log instead of conflicting at sequence zero.
§Errors
Returns LiminalError::PublishFailed when the durable channel cannot be
initialized over store, including when recovering the per-partition
sequence counters from the store fails.
Sourcepub const fn config(&self) -> &ChannelConfig
pub const fn config(&self) -> &ChannelConfig
Returns the channel configuration used to create this handle.
Sourcepub fn publish<Payload>(&self, payload: Payload) -> Result<(), LiminalError>
pub fn publish<Payload>(&self, payload: Payload) -> Result<(), LiminalError>
Publishes a payload to the channel with the default publisher identity.
§Errors
Returns a LiminalError when the channel cannot accept the payload or the schema rejects it.
Sourcepub fn publish_from<Payload>(
&self,
publisher_id: impl Into<PublisherId>,
payload: Payload,
) -> Result<(), LiminalError>
pub fn publish_from<Payload>( &self, publisher_id: impl Into<PublisherId>, payload: Payload, ) -> Result<(), LiminalError>
Publishes a payload with an explicit publisher identity.
§Errors
Returns a LiminalError when the channel cannot accept the payload or the schema rejects it.
Sourcepub fn publish_with_context<Payload>(
&self,
payload: Payload,
publisher_id: PublisherId,
causal_context: Option<CausalContext>,
) -> Result<(), LiminalError>
pub fn publish_with_context<Payload>( &self, payload: Payload, publisher_id: PublisherId, causal_context: Option<CausalContext>, ) -> Result<(), LiminalError>
Publishes a payload with explicit publisher and causal metadata.
§Errors
Returns a LiminalError when the channel cannot accept the payload or the schema rejects it.
Sourcepub fn publish_with_delivery<Payload>(
&self,
payload: Payload,
publisher_id: PublisherId,
causal_context: Option<CausalContext>,
) -> Result<ChannelDelivery, LiminalError>
pub fn publish_with_delivery<Payload>( &self, payload: Payload, publisher_id: PublisherId, causal_context: Option<CausalContext>, ) -> Result<ChannelDelivery, LiminalError>
Publishes a payload and reports a genuine delivery ack.
Returns a ChannelDelivery whose delivered_count is the number of
local subscribers the message was actually delivered to. A caller that
needs to know the message was ACCEPTED by a subscriber (not merely
buffered/published) inspects ChannelDelivery::is_delivered. This is the
channel-library half of the 13-L1 delivery-ack signal; the publish-without-
delivery methods stay unchanged for existing callers.
§Errors
Returns a LiminalError when the channel cannot accept the payload or the schema rejects it.
Sourcepub fn publish_recording<Payload>(
&self,
payload: Payload,
publisher_id: PublisherId,
causal_context: Option<CausalContext>,
idempotency_key: Option<&str>,
record: &mut PublishRecord,
) -> Result<ChannelDelivery, LiminalError>
pub fn publish_recording<Payload>( &self, payload: Payload, publisher_id: PublisherId, causal_context: Option<CausalContext>, idempotency_key: Option<&str>, record: &mut PublishRecord, ) -> Result<ChannelDelivery, LiminalError>
Publishes as ChannelHandle::publish_with_delivery does (and, with
an idempotency_key, as
ChannelHandle::publish_with_idempotency_key does), and fills
record with what it saw: the subscriber pid of every local
subscriber whose inbox queued the message, with the instant it did
(exactly ChannelDelivery::delivered_count of them), and, on a
durable channel, the instant its append completed. A subscriber whose
predicate matched and whose inbox refused the message is counted in
ChannelDelivery::matched_count and is not a recipient.
record is cleared first and its allocation is reused, so a caller
that keeps one record allocates only while it grows to the channel’s
widest fan-out. A publish that fails, or is refused at the watermark,
names no recipient and hands its allocation back, with one exception:
a publish whose channel actor took the command and then never answered
(it stopped, or the wait for it ended) leaves no allocation, because
the one it lent went with that actor. A durable publish whose append
committed before it failed (it is then
LiminalError::PublishUnresolved) still says when the append
completed: the row is stored. Any other failure leaves the record
empty.
§Errors
Returns the errors of ChannelHandle::publish_with_delivery.
Sourcepub fn publish_batch_with_delivery(
&self,
payloads: &[Vec<u8>],
publisher: &PublisherId,
causal: Option<&CausalContext>,
) -> Result<Vec<ChannelDelivery>, LiminalError>
pub fn publish_batch_with_delivery( &self, payloads: &[Vec<u8>], publisher: &PublisherId, causal: Option<&CausalContext>, ) -> Result<Vec<ChannelDelivery>, LiminalError>
Appends and flushes a durable batch once, then delivers each row in its stored order.
An empty batch does no work. The single-record publication path is unchanged. Flush observers must hand publication off without re-entering this channel’s append lock.
§Errors
Returns an error for an ephemeral channel, an empty publisher, invalid payloads or failed storage.
A committed row whose delivery is unconfirmed returns LiminalError::PublishUnresolved.
Sourcepub fn current_schema_id(&self) -> Result<SchemaId, LiminalError>
pub fn current_schema_id(&self) -> Result<SchemaId, LiminalError>
Returns the schema version currently owned by the channel actor.
§Errors
Returns a LiminalError when the channel actor cannot be read.
Sourcepub fn evolve_schema_add_field(
&self,
name: impl Into<String>,
field_schema: Value,
default: Value,
) -> Result<SchemaId, SchemaValidationError>
pub fn evolve_schema_add_field( &self, name: impl Into<String>, field_schema: Value, default: Value, ) -> Result<SchemaId, SchemaValidationError>
Evolves the channel schema by adding a defaulted field without disconnecting subscribers.
§Errors
Returns SchemaValidationError when the schema cannot be evolved.
Sourcepub fn subscribe(&self) -> Result<SubscriptionHandle, LiminalError>
pub fn subscribe(&self) -> Result<SubscriptionHandle, LiminalError>
Subscribes to the channel, receiving every published message.
§Errors
Returns a LiminalError when a subscription cannot be created.
Sourcepub fn subscribe_with_install(
&self,
install: InboxInstall,
) -> Result<SubscriptionHandle, LiminalError>
pub fn subscribe_with_install( &self, install: InboxInstall, ) -> Result<SubscriptionHandle, LiminalError>
Subscribes with a server-connection InboxInstall: the §5 shared byte
budget, per-inbox fairness cap, and R3 wake notifier are installed on the
inbox AT CONSTRUCTION — strictly before the registration is published to
the channel actor — so no envelope can be admitted uncharged, past the
depth cap, or without a wake (the pre-install window is structurally
closed, not merely narrowed).
§Errors
Returns a LiminalError when a subscription cannot be created.
Sourcepub fn subscribe_filtered<F>(
&self,
predicate: F,
) -> Result<SubscriptionHandle, LiminalError>
pub fn subscribe_filtered<F>( &self, predicate: F, ) -> Result<SubscriptionHandle, LiminalError>
Subscribes with a delivery predicate: only messages for which predicate
returns true are delivered to this subscriber. The predicate is owned
and evaluated by the actor process (R3).
§Clustering
The predicate filters local-node publishes only. Under clustering (SRV-005), messages published on a remote node are delivered to this subscriber ungated — the predicate is a non-serializable closure and is not propagated across the wire, so remote nodes cannot evaluate it. If you need filtering to hold for cross-node traffic, filter again on receipt rather than relying on this predicate alone.
§Errors
Returns a LiminalError when a subscription cannot be created.
Sourcepub fn subscribe_consumer(
&self,
consumer: &str,
install: InboxInstall,
) -> Result<SubscriptionHandle, LiminalError>
pub fn subscribe_consumer( &self, consumer: &str, install: InboxInstall, ) -> Result<SubscriptionHandle, LiminalError>
Opens a stable durable consumer at its subscription-owned checkpoint. Ephemeral channels retain the same bounded live subscription.
§Errors
Subscription construction, cursor recovery, or replay failed.
Sourcepub fn unsubscribe(
&self,
subscription: &SubscriptionHandle,
) -> Result<(), LiminalError>
pub fn unsubscribe( &self, subscription: &SubscriptionHandle, ) -> Result<(), LiminalError>
Unsubscribes the subscriber owning subscription by its process pid.
§Errors
Returns a LiminalError when the unsubscribe command fails.
Sourcepub fn flush(&self) -> Result<(), LiminalError>
pub fn flush(&self) -> Result<(), LiminalError>
Flushes buffered durable channel state to the backing store before shutdown.
§Errors
Returns a LiminalError when the channel actor cannot be inspected or
when the durable store flush fails.
Sourcepub fn subscriber_count(&self) -> Result<usize, LiminalError>
pub fn subscriber_count(&self) -> Result<usize, LiminalError>
Returns the number of currently-active subscribers on the channel actor.
§Errors
Returns a LiminalError when the actor cannot service the query.
Sourcepub fn close(&self) -> Result<(), LiminalError>
pub fn close(&self) -> Result<(), LiminalError>
Closes the channel gracefully, stopping the actor process.
§Errors
Returns a LiminalError when the channel cannot be shut down.
Sourcepub fn is_actor_spawned(&self) -> bool
pub fn is_actor_spawned(&self) -> bool
Whether this channel’s actor has been spawned — without spawning it.
This is the one accessor on the handle that observes the lazy-spawn
state instead of consuming it. Every other accessor
(subscriber_count,
close) routes through the private core(), which
spawns the actor on demand, so reading “is there an actor?” through any
of them destroys the very property being read. A handle that spawns
lazily has a genuine, observable idle/live state, and a consumer that
needs to know it — a registry reporting which of its channels are inert,
a cost accountant bounding what mere configuration costs — otherwise has
to choose between not knowing and changing the answer by asking.
It reads the memoised spawn slot and nothing else: no supervisor call,
no schema clone, no ensure_running. That last exclusion is the point
of the restriction — ensure_running RESTARTS a dead actor, so an
implementation routed through it would repair the state rather than
report it.
§What false and true mean
The slot holds Result<Arc<ChannelActorCore>, String>: a spawn that
failed is memoised as Err and, because the slot is one-shot, is never
retried — every later operation on this handle fails with that stored
message. So a failed spawn ATTEMPT leaves no actor and can never acquire
one, and this method answers false for it, exactly as it does for a
channel nobody has touched. false therefore means “no actor core
exists” and deliberately does not distinguish “never attempted” from
“attempted and permanently failed” — neither has an actor.
true means the actor core exists, not that its process is currently
alive: an actor whose pid has died stays true until the next real
operation restarts it through the supervisor. Liveness is a stronger
question than this method asks, and answering it would require running
the repair path this method exists to avoid.