Source code for melder.utilities.custom_exceptions.managed_spell_exhausted_error

from typing import Optional

from melder.utilities.custom_exceptions.meld_execution_error import MeldExecutionError


[docs] class ManagedSpellExhaustedError(MeldExecutionError): """ Purpose: Signal that a meld could not lease an object of an `Existence.managed_spell_quantity` spell because its pool had no place: a `limited_quantity` pool with every object out, or a `queue` pool that stayed full until its timeout. Names the spell, the mode, the numbers and the two ways out, instead of a bare refusal. Raised When: A managed site misses (no idle object in its pool) and `ManagedSpellQuantity.reserve()` cannot reserve a place: `limited_quantity` at `count >= limit` with nothing idle, or `queue` after waiting its `managed_spell_timeout_seconds` without a release, a destroy or a failed build freeing a place. Nothing has been built when it is raised, and the pool's count is unchanged. `elastic` pools never raise it. What To Do About It: Give an object back - `ReleaseManagedSpell().release(obj)`, or leave the `with` block of a lease - before melding another, or bind the spell with a higher `managed_spell_limit` (and, for `queue`, a longer `managed_spell_timeout_seconds`). `ReleaseManagedSpell().describe(cls)` shows each pool's count, idle and out objects. Contract: - A `MeldExecutionError`: code that catches `MeldExecutionError` keeps catching it. `spell_id` and `spell_name` name the managed spell; `node_id`, `param_name` and `inner` are None (nothing was called). - `mode` is the pool's mode name (`"limited_quantity"` or `"queue"`), `limit` its limit and `timeout_seconds` the queue wait (None for `limited_quantity`). - Built only through `limited(...)` and `queue(...)`, which own the message texts. Owned State: - Inherited `spell_id`, `spell_name`, `node_id`, `param_name`, `inner`. - `mode`, `limit`, `timeout_seconds`: the refusing pool's policy. Registration: A public exception type; import, raise and catch freely. Like every Melder class it is refused as a spell registration. Subsystem Context: One of the `utilities/custom_exceptions/` types; the managed-pool form of `MeldExecutionError`. It imports nothing from the runtime, so the pool (`ManagedSpellQuantity`, in the conduit creations package) depends on it and not the other way round. System Context: Fires in the resolution layer at meld, from the cold miss of a managed site, before any construction. Successful leases never evaluate it. AGENT_ACCESS: public AGENT_PURPOSE: access: public. Raised at meld when a managed spell's pool has no place: limited_quantity with every object out, or queue after its timeout. Release an object (ReleaseManagedSpell().release(obj)) or bind a higher managed_spell_limit / managed_spell_timeout_seconds. """ __slots__ = ( "mode", "limit", "timeout_seconds", ) def __init__( self, *, spell_id: str, spell_name: str, message: str, mode: str, limit: int, timeout_seconds: Optional[float] = None, ) -> None: """ Construct an exhausted-pool failure. Args: spell_id: The managed spell's spell_id. spell_name: Human-readable name of that spell. message: Remediation-bearing message; `limited(...)` and `queue(...)` write it. mode: Name of the refusing pool's mode, `"limited_quantity"` or `"queue"`. limit: The pool's limit: the most objects alive at once. timeout_seconds: The queue wait that ran out; None for `limited_quantity`. Contract: - Preserves every `MeldExecutionError` field; `node_id`, `param_name` and `inner` stay None. Returns: None. """ super().__init__( spell_id=spell_id, spell_name=spell_name, message=message, ) self.mode: str = mode self.limit: int = limit self.timeout_seconds: Optional[float] = timeout_seconds
[docs] @classmethod def limited(cls, *, spell_id: str, spell_name: str, limit: int) -> ManagedSpellExhaustedError: """ Build the refusal of a `limited_quantity` pool that has every object out. Contract: - The message names the spell, the mode and the limit, and the two remedies: release an object first, or bind a higher `managed_spell_limit`. - Pure: builds the error, raises nothing. Args: spell_id: The managed spell's spell_id. spell_name: Its display name. limit: The pool's limit. Returns: ManagedSpellExhaustedError: The error, mode `"limited_quantity"`, no timeout. """ return cls( spell_id=spell_id, spell_name=spell_name, message=( f"Managed spell '{spell_name}' (limited_quantity, limit {limit}) has all {limit} objects out. " f"Release one with ReleaseManagedSpell().release(obj) before melding another, or bind it with a " f"higher managed_spell_limit." ), mode="limited_quantity", limit=limit, )
[docs] @classmethod def queue( cls, *, spell_id: str, spell_name: str, limit: int, timeout_seconds: float, ) -> ManagedSpellExhaustedError: """ Build the refusal of a `queue` pool whose wait ran out. Contract: - The message names the spell, the mode, the limit and the timeout (printed with `:g`, so 2.0 reads "2" and 0.25 "0.25"), and the remedies: release an object, or bind a higher `managed_spell_limit` or `managed_spell_timeout_seconds`. - Pure: builds the error, raises nothing. Args: spell_id: The managed spell's spell_id. spell_name: Its display name. limit: The pool's limit. timeout_seconds: The wait that ran out, in seconds. Returns: ManagedSpellExhaustedError: The error, mode `"queue"`, with its timeout. """ return cls( spell_id=spell_id, spell_name=spell_name, message=( f"Managed spell '{spell_name}' (queue, limit {limit}) had no object free within " f"{timeout_seconds:g} s. Release one with ReleaseManagedSpell().release(obj), or bind it with a " f"higher managed_spell_limit or managed_spell_timeout_seconds." ), mode="queue", limit=limit, timeout_seconds=timeout_seconds, )