pub struct Checkout { /* private fields */ }Expand description
One worker dedicated to one REPL session.
Obtained from crate::Pool::checkout. Checkout::finish returns the
worker to the pool; dropping without finishing kills the worker instead —
mid-execution state cannot be trusted back into the pool.
§Cancellation
Turn futures (feed, resume*, dump, …) are not resumable after
being dropped mid-flight: the request may already be on the wire (or a
mount’s host I/O abandoned mid-service), so the protocol state is
unknowable. The checkout notices on its next call,
discards the worker, and fails with PoolError::Protocol; finish on
such a session likewise discards the worker rather than returning it.
Implementations§
Source§impl Checkout
impl Checkout
Sourcepub async fn restore(
&mut self,
state: Vec<u8>,
mounts: Vec<MountSpec>,
on_print: OnPrint<'_>,
) -> Result<(Option<TurnEvent>, Option<String>), PoolError>
pub async fn restore( &mut self, state: Vec<u8>, mounts: Vec<MountSpec>, on_print: OnPrint<'_>, ) -> Result<(Option<TurnEvent>, Option<String>), PoolError>
Restores a dumped session into this checkout’s freshly configured (but
not-yet-fed) worker, returning the re-announced suspension event when the
dump was taken mid-feed (None for an idle, between-feeds dump).
This is the low-level restore both session.load_session (idle dumps) and
session.load_snapshot (suspended dumps) drive: the caller inspects the
returned Option to tell which kind of dump it was and reject a
mismatch. Only valid before the worker has been fed (the child rejects a
Load once a repl exists).
mounts re-establish a suspended feed’s mounts, which are never part of
the dump (they are host configuration the parent services itself). Pass
the same mounts the original feed used, so the resumed feed’s covered
calls can still be answered by Checkout::resume_from_mounts. A dump
taken mid-OS-call re-announces the call in full, so the returned event
is that same TurnEvent::OsCall — restoring never answers it here.
The worker caps snapshot resource limits at the checkout’s configured limits.
Stricter snapshot limits and elapsed execution time remain in effect.
The parent adopts these effective limits from the worker’s reply, but keeps
its configured ones as ceilings, so a lying worker cannot loosen them.
The suspension count restarts at zero.
Returns the re-announced suspension (Some — a suspended dump) or None
(an idle dump), paired with the worker’s adopted script name (the dump’s,
not the Configure one), which the parent surfaces in restored snapshots.
§Snapshot trust
The caller must verify the dump’s provenance and integrity before restoring it. Invalid snapshots have no correctness or availability guarantees. Successful loading is not authentication or validation.
Against a relay that stores sessions, state may instead be a session ID
it minted. Loading one always starts a new session, with its own
Checkout::session_id, from the state last stored under that ID.
Sourcepub async fn feed(
&mut self,
code: impl Into<String>,
inputs: impl Into<NamedValues>,
mounts: Vec<MountSpec>,
skip_type_check: bool,
on_print: OnPrint<'_>,
) -> Result<TurnEvent, PoolError>
pub async fn feed( &mut self, code: impl Into<String>, inputs: impl Into<NamedValues>, mounts: Vec<MountSpec>, skip_type_check: bool, on_print: OnPrint<'_>, ) -> Result<TurnEvent, PoolError>
Executes one snippet against the session. Inputs become sandbox
globals; mounts apply to this feed only and are serviced by the parent
(specs with overlapping host directories fail here, before any frame is
sent, as a session-preserving PoolError::Runtime). The session’s
first feed sets the sandbox working directory to its first mount’s
virtual path, or / without mounts; later feeds keep the directory
(os.chdir included) unless Checkout::feed_with_cwd switches it.
Returns the first suspension (or completion); print() output streams
to on_print throughout.
§Errors
PoolError::Runtime / PoolError::Typing leave the session
usable; all other errors mean the worker was discarded.
Sourcepub async fn feed_with_cwd(
&mut self,
code: impl Into<String>,
inputs: impl Into<NamedValues>,
mounts: Vec<MountSpec>,
cwd: Option<&str>,
skip_type_check: bool,
on_print: OnPrint<'_>,
) -> Result<TurnEvent, PoolError>
pub async fn feed_with_cwd( &mut self, code: impl Into<String>, inputs: impl Into<NamedValues>, mounts: Vec<MountSpec>, cwd: Option<&str>, skip_type_check: bool, on_print: OnPrint<'_>, ) -> Result<TurnEvent, PoolError>
Checkout::feed with an explicit switch of the sandbox working
directory before the feed: an absolute POSIX virtual path that
os.getcwd() reports and relative paths resolve against. None keeps
the session’s current directory, which the first feed defaults to its
first mount (else /).
§Errors
A relative or NUL-containing cwd is a session-preserving
PoolError::Runtime (ValueError), raised before any frame is sent.
Sourcepub async fn resume(
&mut self,
value: ResumeValue,
on_print: OnPrint<'_>,
) -> Result<TurnEvent, PoolError>
pub async fn resume( &mut self, value: ResumeValue, on_print: OnPrint<'_>, ) -> Result<TurnEvent, PoolError>
Answers a TurnEvent::FunctionCall or TurnEvent::OsCall.
Sourcepub async fn resume_from_mounts(
&mut self,
on_print: OnPrint<'_>,
) -> Result<Option<TurnEvent>, PoolError>
pub async fn resume_from_mounts( &mut self, on_print: OnPrint<'_>, ) -> Result<Option<TurnEvent>, PoolError>
Answers a pending TurnEvent::OsCall from this feed’s mounts, when
they cover it.
Ok(None) means no mount covers the call (or the feed has none): the
suspension is left intact for the caller to answer itself, typically via
its own os handler and then Checkout::resume. Ok(Some(event))
means a mount serviced the call — including servicing it into an error
such as PermissionError — and the feed ran on to event.
This is how mounts are reached now that every OS call surfaces: an
auto-answering driver tries mounts first and falls back to its handler,
while a caller driving suspensions by hand can ignore mounts entirely.
Path containment inside covered calls is enforced by the MountTable.
Covered calls perform real host filesystem I/O, serviced on tokio’s blocking pool so a stalled volume cannot pin a runtime worker. Dropping this future mid-servicing abandons the feed’s mount state and is treated exactly like a cancellation mid-turn: the worker is discarded on the next call.
Sourcepub async fn resume_name_lookup(
&mut self,
result: impl Into<NameLookupResult>,
on_print: OnPrint<'_>,
) -> Result<TurnEvent, PoolError>
pub async fn resume_name_lookup( &mut self, result: impl Into<NameLookupResult>, on_print: OnPrint<'_>, ) -> Result<TurnEvent, PoolError>
Answers a TurnEvent::NameLookup with a NameLookupResult (or a
MontyObject, an Option<MontyObject> where None is Undefined, or
a MontyException for Error): a value resolves the name; Undefined
makes the sandbox raise NameError for a plain lookup, or
AttributeError when the lookup carried an object_id (a lazy
attribute on a host-backed object — a class instance or class type);
Error raises the host’s exception in the sandbox, bypassing
hasattr() / getattr() defaults the way a raising property does.
Sourcepub async fn resume_futures(
&mut self,
results: Vec<(u32, ResumeValue)>,
on_print: OnPrint<'_>,
) -> Result<TurnEvent, PoolError>
pub async fn resume_futures( &mut self, results: Vec<(u32, ResumeValue)>, on_print: OnPrint<'_>, ) -> Result<TurnEvent, PoolError>
Answers a TurnEvent::ResolveFutures with results for some or all
pending call ids. Each result must be Return or Error — a future
cannot resolve to another future or to “not found”.
Also accepts exactly one matching result for a call with allow_eager_await set.
Sourcepub async fn install_dependencies(
&mut self,
requirements: Vec<String>,
) -> Result<(), PoolError>
pub async fn install_dependencies( &mut self, requirements: Vec<String>, ) -> Result<(), PoolError>
Installs third-party Python packages into the session, making them
importable by subsequent feeds. Session-scoped and repeatable; an empty
requirements list is a no-op.
Only an embedded-CPython worker honors this. The
monty sandbox worker has no host interpreter to install for and a uv
install failure both surface as PoolError::Runtime (the latter
carrying uv’s stderr); the session stays usable in either case. Bounded
by the pool’s request_timeout, so raise it for large dependency sets.
Each requirement is validated here, at the pool boundary, before any
frame is sent: a string that uv would parse as an option rather than a
package specifier is rejected with PoolError::Runtime (a
ValueError). See validate_requirement for the rationale.
Sourcepub async fn dump(&mut self) -> Result<Vec<u8>, PoolError>
pub async fn dump(&mut self) -> Result<Vec<u8>, PoolError>
Serializes the session (idle or suspended) into opaque bytes that
Checkout::restore can restore — including into a
different worker after this one crashes. The session stays live.
Sourcepub async fn finish(self) -> Result<(), PoolError>
pub async fn finish(self) -> Result<(), PoolError>
Ends the session and returns the worker to the pool.
Consumes the checkout. On error the worker is discarded (and the error reported), but the pool remains healthy either way.
Sourcepub fn worker_id(&self) -> Option<u64>
pub fn worker_id(&self) -> Option<u64>
Stable identity within this pool, independent of PID reuse or transport.
Returns None after the worker has been released or discarded.
Sourcepub fn pid(&self) -> Option<u32>
pub fn pid(&self) -> Option<u32>
OS process id of the worker, when it is a local subprocess (None for a
remote WebSocket worker, or a finished checkout). Diagnostics/tests.
Sourcepub fn session_id(&self) -> Option<&[u8]>
pub fn session_id(&self) -> Option<&[u8]>
The opaque session ID a storing relay minted, which Checkout::restore
resumes from any process. None for local workers and ephemeral sessions.
Sourcepub async fn turn_raw(
&mut self,
request: &ParentRequest,
on_event: OnRawEvent<'_>,
) -> Result<ChildEvent, PoolError>
pub async fn turn_raw( &mut self, request: &ParentRequest, on_event: OnRawEvent<'_>, ) -> Result<ChildEvent, PoolError>
Sends request and returns the child’s turn-ending event, as protobuf —
no conversion to TurnEvent.
For callers that already speak the wire (a relay bridging a remote
client): rebuilding a ChildEvent frame from a TurnEvent means
hand-inverting the whole protocol, so this hands back what the child
actually sent. on_event sees each streamed Print before the
turn-ender.
Bypasses this checkout’s session bookkeeping (pending,
feed_mounts, restored_script_name, session_id) — never interleave
with feed/resume/restore: the driver reads what a reply names from
the frame it forwards. Worker lifecycle, poisoning and parent-side
limits work as on the typed path; a raw Load re-adopts its budget like
Checkout::restore. A FatalError
(or WebSocket ShutdownDump) turn-ender is returned so the driver can
forward it, but discards the worker first — later calls report
PoolError::Finished; a raw driver is never auto-resumed.
§Security
request is typically a remote client’s, so it is treated as hostile:
Configure/Reset/Shutdown are refused here (a client could
otherwise Reset away the operator-chosen resource limits and
re-Configure its own). A Load’s bytes DO reach the worker’s
deserialiser — the driver must verify a dump is one it issued
(monty-server loads only records it stored and signed) before passing
it in.
§Errors
As Checkout::feed: a dead worker, a protocol violation, or a turn
that outlived request_timeout or the remaining feed/turn budget.