Skip to main content

Checkout

Struct Checkout 

Source
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

Source

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.

Source

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.

Source

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.

Source

pub async fn resume( &mut self, value: ResumeValue, on_print: OnPrint<'_>, ) -> Result<TurnEvent, PoolError>

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Trait Implementations§

Source§

impl Drop for Checkout

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V