Skip to main content

UpgradeInstruction

Enum UpgradeInstruction 

Source
pub enum UpgradeInstruction {
    LoadModule {
        module: String,
    },
    StateChange {
        script: PathBuf,
    },
    SoftPurge {
        module: String,
    },
    Purge {
        module: String,
    },
    Restart,
}
Expand description

One upgrade instruction. The set mirrors OTP’s appup low-level instructions: enough to express every common upgrade pattern, few enough that the wasm-operator can implement each deterministically.

Variants§

§

LoadModule

Load a new wasm module alongside the current one — the analog of OTP’s code:load_module/1. Both versions remain in memory after this instruction; in-flight requests stay on the old version, new requests route to the new version.

Fields

§module: String
§

StateChange

Run a state-migration tatara-lisp file. Receives the old state

  • the prior version string; returns the new state. Analog of gen_server:code_change/3.

Fields

§script: PathBuf
§

SoftPurge

Wait for in-flight requests on a named module to drain, then GC it — the analog of code:soft_purge/1. Default cooldown is 60s; longer-running requests block the upgrade.

Fields

§module: String
§

Purge

Discard a named module immediately, without waiting for drain — the analog of code:purge/1. Used when we don’t care about in-flight callers (cron, oneShot).

Fields

§module: String
§

Restart

Fall back to a full restart for this entry. Used when a typed upgrade is impossible (e.g. wasm component world incompatible).

Implementations§

Source§

impl UpgradeInstruction

Source

pub const fn discriminant(&self) -> &'static str

Stable variant discriminant — auto-generated by #[derive(Discriminant)]. The string IS the wire identifier for metrics labels / audit-log tags / rate-limit keys; renaming an existing variant is a breaking change.

Source§

impl UpgradeInstruction

Source

pub const fn is_load_module(&self) -> bool

Source

pub const fn is_state_change(&self) -> bool

Source

pub const fn is_soft_purge(&self) -> bool

Source

pub const fn is_purge(&self) -> bool

Source

pub const fn is_restart(&self) -> bool

Source§

impl UpgradeInstruction

Source

pub fn validate(&self) -> Result<(), UpgradeError>

Validate the instruction’s typed shape. Path existence is checked separately by crate::layout::StandardLayout.

The per-variant scalar the value-shape gates fire against is read through this method’s two sibling accessors — the String-carrying axis via Self::declared_module (the LoadModule / SoftPurge / Purge variants unifying on their K8s DNS-1123-label :module reference) and the PathBuf- carrying axis via Self::declared_path (the StateChange variant’s tatara-lisp :script) — rather than the per-arm Self::LoadModule { module } | Self::SoftPurge { module } | Self::Purge { module } pattern the module-axis previously open-coded and the per-arm Self::StateChange { script } the script-axis previously open-coded. Every scalar this enum carries now flows through one of the two Option<&…> accessors, so a future extension of either axis (a fifth module-bearing variant, an operator-side pre-parsed scalar cache the accessors materialize behind the same return contract, an M4 typed sub-slot the accessors could route alongside the existing scalar) migrates as a single edit on the accessor rather than a coordinated rewrite of every downstream value-shape gate. Restart (the only variant that carries neither scalar) falls through both Option checks and returns Ok(()) — the terminal-fallback shape the Self::Restart variant doc pins.

Source

pub fn declared_module(&self) -> Option<&str>

The :module scalar carried by this instruction — the K8s DNS-1123-label OTP-appup caixa-name reference every Self::LoadModule / Self::SoftPurge / Self::Purge variant declares against, and every author expects feira lint to name verbatim in per-instruction diagnostics. Returns None on Self::StateChange (which carries a :script — closed by the sibling Self::declared_path) and on Self::Restart (which carries no data at all, the OTP terminal-fallback shape).

Sibling in shape to Self::declared_path on the second and final scalar-carrying axis of UpgradeInstruction: declared_path closes the PathBuf-carrying arm (StateChange); declared_module closes the String-carrying arms (LoadModule / SoftPurge / Purge). Every scalar the enum carries now routes through one of the two Option<&…> accessors — a caller that doesn’t care which variant declared the scalar reads through one if let Some(…) rather than a per-variant pattern match. The pair is the enum-variant- unifying peer of the per-mesh-slot-atom scalar-accessor family on the M3 side (crate::WitContract::source / crate::WitContract::destination / crate::WitContract::world_ref closing :contratos; crate::Entrada::hostname / crate::Entrada::destination closing :entrada; crate::Membro::nome / crate::Membro::versao_requirement closing :membros) and on the M2 side (crate::UpgradeFromEntry::prior_versao closing per-entry :from; the crate::LimitsSpec / crate::BehaviorSpec closed families; the crate::ChildSpec closed OTP-shape supervisor family) — those peer accessors return a struct field verbatim; this pair unifies enum- variant-carried scalars into one accessor per typed axis.

Byte-for-byte from the typed variant’s own String storage; no cloning, no re-parsing. A future extension of the axis (an M4 typed sub-slot the module string is derived from, an operator-side pre-parsed caixa-name cache the accessor could materialize behind the same &str return contract, a fifth module-bearing OTP-appup variant the enum grows) migrates as a single caixa-core edit rather than a coordinated rewrite of every downstream module-axis consumer (currently Self::validate’s DNS-1123-label gate through [validate_module]; extensible to future consumers on the same axis without further per-variant match sites).

Source

pub fn declared_path(&self) -> Option<&PathBuf>

If the instruction references an on-disk path, return it — used by the layout checker to verify the path resolves.

Sibling on the PathBuf-carrying axis to Self::declared_module on the String-carrying axis: declared_path closes the StateChange arm’s :script; declared_module closes the LoadModule / SoftPurge / Purge arms’ :module. Together they route every scalar this enum carries through one of two Option<&…> accessors, so Self::validate’s value-shape gates dispatch on the accessor return rather than a per-variant pattern match on the enum shape itself.

Four per-UpgradeInstruction consumers now key off this accessor’s PathBuf-carrying axis: Self::validate’s per-StateChange sandbox-path fan-out, [crate::layout::StandardLayout::verify]’s per-StateChange script-existence fan-out at caixa-core/src/layout.rs:1058, the within-entry UpgradeFromEntry::validate_state_change_singularity (2bf3ce5) per-StateChange script-projection fan-out, and the cross-slot validate_upgrade_from_against_behavior :upgrade-from ↔ :behavior composition gate’s per-StateChange detection loop — every downstream consumer of the PathBuf-carrying axis reaches through this one dispatch, so a future accessor extension (an M4 typed sub-slot the script path is derived from, an operator-side pre-resolved-path cache the accessor materializes behind the same Option<&PathBuf> return contract, a fifth PathBuf-bearing OTP-appup variant the enum grows) migrates as a single caixa-core edit rather than a coordinated rewrite of four call sites.

Source

pub const fn is_cleanup(&self) -> bool

Substrate-canonical per-UpgradeInstruction OTP-appup cleanup- family arm-discriminator predicate every within-entry cross- instruction cleanup-facing gate keys off — true iff self is Self::SoftPurge (code:soft_purge/1 analog: drain the named module until no process is running it, then GC) or Self::Purge (code:purge/1 analog: discard the named module immediately, without waiting for drain), the two OTP two-phase-code-load cleanup arms the closed-set enum’s non-terminal / non-migration / non-load variants exhaust. Every non-cleanup arm (Self::LoadModule on the paired two-phase-load half, Self::StateChange on the gen_server:code_change/3-analog migration axis, Self::Restart on the OTP terminal-fallback shape) returns false.

Prior to this lift the Self::SoftPurge { module } | Self::Purge { module } two-arm cleanup-family pattern- match sat inline at three within-entry cross-instruction gate sites, each hand-rolling its own copy of the union with no compile-time link back to the substrate primitive’s closed-set arm-family: UpgradeFromEntry::validate_purge_ordering at caixa-core/src/upgrade.rs:570 (guarded arm firing UpgradeError::PurgeWithoutPriorLoad on any cleanup arriving before a preceding Self::LoadModule), UpgradeFromEntry::validate_state_change_before_cleanup at caixa-core/src/upgrade.rs:689 (sticky-once latch recording the first-encountered cleanup so a subsequent Self::StateChange fires UpgradeError::StateChangeAfterCleanup), and UpgradeFromEntry::validate_cleanup_singularity at caixa-core/src/upgrade.rs:800 (per-module cleanup-target dedup ejecting UpgradeError::DuplicateCleanup on the second cleanup targeting the same :module). Three open- coded per-arm-union pattern-matches that expressed no compile-time link back to the substrate primitive. A future fifth cleanup-shaped variant (a Discard variant the code:delete/1 peer inspires that folds under the same two-phase-load cleanup partition, an M4 SoftPurge split into SoftPurgeCoop / SoftPurgeForce peers as the drain- cool-down policy grows a two-arm shape, an operator-side pre-resolved cleanup-decision cache the predicate could route through the same bool return contract) would have had to be threaded through every open-coded per-arm-union pattern-match in lockstep or one gate would silently classify the new arm outside the cleanup family while the peer gates classified it in (or vice versa) — a classification split across the three within-entry cross- instruction gates at build time that lands far from the source UpgradeInstruction declaration with no field naming which gate carries the drifted arm-set. Lifting the resolution to a typed predicate on the substrate primitive means every downstream cleanup-facing consumer of the UpgradeInstruction closed-set enum reaches for exactly one typed dispatch — the resolver’s arm-set migrates as a unit on any future arm addition composing under this predicate’s || chain.

Sibling in shape to the peer gen_platform::IsVariant- derive-generated Self::is_restart terminal-fallback arm-discriminator predicate on the same closed-set UpgradeInstruction enum (each names an OTP-appup arm- family partition as one typed dispatch on the substrate primitive; is_restart on the single-arm terminal- fallback family, is_cleanup on the two-arm cleanup family), extended here from the single-arm case onto the two-arm arm-family union case. Composes through the gen_platform::IsVariant-derive-generated Self::is_soft_purge / Self::is_purge per-variant predicates rather than an open-coded raw matches! pattern-match, so a future rebrand on either underlying per-arm classifier flows through this predicate’s one body without a coordinated per-consumer rewrite across the three within-entry cross-instruction gates that route through it. Peer of the sibling per-:contratos shape-family union predicates crate::WitContract::is_http / crate::WitContract::is_pubsub / crate::WitContract::is_store on the M3 mesh-slot per-:wit world-ref axis (each unions a per-shape WIT-prefix rule the substrate primitive’s arm- family partition names as one typed dispatch) — the same “one typed dispatch on the substrate primitive, thin projections at each consumer” discipline extended onto the M2 :upgrade-from :instructions per-UpgradeInstruction cleanup-family axis.

The name is_cleanup maps directly onto the canonical OTP-appup vocabulary (INSPIRATIONS §II.4 verbatim: “2. code:soft_purge/1 — wait until no process is running v1, then discard. (code:purge/1 kills v1 immediately if you don’t care.)” — the two code:*_purge/1 operations are the two-phase-load contract’s cleanup half, paired under one concept), and the peer [Self::validate_cleanup_singularity] / UpgradeError::DuplicateCleanup / UpgradeError::PurgeWithoutPriorLoad / UpgradeError::StateChangeAfterCleanup surface already reaches for the same “cleanup” vocabulary in identifier + diagnostic form.

Trait Implementations§

Source§

impl Clone for UpgradeInstruction

Source§

fn clone(&self) -> UpgradeInstruction

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for UpgradeInstruction

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'de> Deserialize<'de> for UpgradeInstruction

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Eq for UpgradeInstruction

Source§

impl PartialEq for UpgradeInstruction

Source§

fn eq(&self, other: &UpgradeInstruction) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl Serialize for UpgradeInstruction

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl StructuralPartialEq for UpgradeInstruction

Source§

impl TypedDispatcher for UpgradeInstruction

Source§

fn variant_kinds() -> Vec<&'static str>

Kebab-case serde tags of every variant in declaration order. Used by substrate emitters (Nix helpers skeleton, Lisp catalog, coverage tests) to enumerate the variant universe.
Source§

fn variant_fields() -> Vec<(&'static str, Vec<&'static str>)>

Field names per variant, paired with the variant’s kebab-case tag. Used by substrate emitters to produce the matching inherit (variant) <fields> Nix patterns.
Source§

fn variant_count() -> usize

Total variant count. Convenience for coverage assertions.

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<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
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> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

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

Source§

type Error = Infallible

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

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

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.