pub enum ControlError {
NoSuchSession(SessionId),
SessionEnded(SessionId),
NoSuchStream {
id: SessionId,
stream: StreamKey,
},
Unsupported {
what: &'static str,
leg: Leg,
transport: &'static str,
},
Profile(TransportProfileError),
Shape(ShapeError),
}Expand description
Why a control-plane request could not be carried out.
Distinct from ProxyError, which describes a proxy that could not be
built or a connection that could not be made. Every variant here is a
request the proxy understood and declined, and each says which of the
three reasons applied: the thing addressed is not there, the thing asked
for cannot be done on that leg over that transport, or the value supplied
was refused by the same check that would have refused it in a
configuration file.
Neither Eq nor #[non_exhaustive], and both omissions are load-bearing.
Eq is unavailable because TransportProfileError reaches an f32.
#[non_exhaustive] is absent so that a caller outside this crate can
match every variant with no wildcard arm — a match that stops compiling
when a variant is added, which is the one place a new refusal reliably
gets noticed.
One variant is #[cfg]-gated: ControlError::Impairment exists only
under the impair feature, which is also the only build in which the
method that returns it exists. A downstream exhaustive match therefore
carries the same #[cfg(feature = "impair")] on that arm. Reaching for a
_ arm to avoid the attribute would satisfy the feature-on build as well
and swallow every later variant with it, which is the whole of what the
missing #[non_exhaustive] buys. It is written in plain code font rather
than linked, because a link from this always-compiled page would not
resolve in a build without the feature — the same convention the crate
page uses for every other feature-gated name.
Variants§
NoSuchSession(SessionId)
No session with this id has ever run on this proxy.
Session ids are minted per TransparentProxy
and are not comparable across proxies, so an id from one proxy handed
to another lands here rather than acting on an unrelated session.
A session that ran and has since ended answers
ControlError::SessionEnded instead; the two are told apart by the
highest id this proxy has ever registered, which is enough because
ids are minted monotonically.
The one id that is here and did exist: a connection accepted but
not yet running. SessionStarted is emitted at accept and
registration happens when the session begins to run, so an id in that
window is in no registry — see ProxyControl::sessions, which says
the same thing about the census. Which of the two refusals such an id
gets is not fixed: the split is made on the highest id ever
registered, and two connections accepted together may reach their run
functions in either order, so an id awaiting registration answers
this unless a later one registered first, in which case it answers
ControlError::SessionEnded. Neither answer is retryable and
neither acts on anything, so the difference is one of wording rather
than of what a caller may then do.
SessionEnded(SessionId)
This proxy ran a session with this id and is no longer running it, or is running it but has stopped taking requests for it.
The ordinary race, and not a fault: a session may end between the
call that listed it and the call that acts on it, and a control
plane that panicked there could not be driven from a timeline. Every
verb that names a SessionId can answer this.
Separate from ControlError::NoSuchSession because the two mean
different things to a caller holding a list: a lookup miss on an id
this proxy never issued says the list came from somewhere else,
while this says the list was right and the session ended underneath
the call. Neither is retryable.
It also carries one case that is neither: a request that could not
be taken, because the target already has
COMMAND_QUEUE_DEPTH requests outstanding and has served
none of them. That is a session or a stream that is not going to
serve them, and the frozen refusal set has no “try again later”
answer to give instead. Reaching it takes sixteen unanswered
requests aimed at one target.
NoSuchStream
The session is live but has no stream under this key.
A key that names a stream which has already ended is reported the same way as one that never existed. The two are not distinguished anywhere in this crate: a stream’s registration is removed as it ends, so there is no record left to tell them apart, and inventing one would mean holding every finished stream’s identity for the life of the session.
Fields
Unsupported
The request is meaningful in general but cannot be carried out on this leg, because of what that leg’s transport is able to expose.
Reported rather than ignored. A leg that quietly declined would leave the caller holding a successful return and a proxy that behaves as though nothing was asked — the failure this crate is least willing to ship, because it is invisible from the outside and survives every green run.
Fields
Profile(TransportProfileError)
A TransportProfile was
refused.
The same check that runs when a profile is supplied in a configuration, reporting the same error, so a profile that a leg would not have started with is not one it can be moved to.
Shape(ShapeError)
A ShapeProfile was refused.
As with ControlError::Profile, this is the construction-time
check rather than a second, looser one.
Trait Implementations§
Source§impl Clone for ControlError
impl Clone for ControlError
Source§fn clone(&self) -> ControlError
fn clone(&self) -> ControlError
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for ControlError
impl Debug for ControlError
Source§impl Display for ControlError
impl Display for ControlError
Source§impl Error for ControlError
impl Error for ControlError
Source§fn source(&self) -> Option<&(dyn Error + 'static)>
fn source(&self) -> Option<&(dyn Error + 'static)>
1.0.0 · Source§fn description(&self) -> &str
fn description(&self) -> &str
use the Display impl or to_string()