Skip to content

Commit 9a6b4ae

Browse files
authored
Update 0xx-spin-factors.md
1 parent 52ce313 commit 9a6b4ae

File tree

1 file changed

+55
-51
lines changed

1 file changed

+55
-51
lines changed

docs/content/sips/0xx-spin-factors.md

Lines changed: 55 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,13 @@ Created: May 20, 2024
1313
## Background
1414

1515
Spin 1.0 shipped with a mechanism for extending the runtime environment with
16-
loosely-coupled host functionality called "host components". As Spin has
17-
evolved, more and more runtime functionality has fallen outside of the scope of
18-
this mechanism, leading to the code for these features spreading out over the
19-
Spin codebase. This not only makes it hard to read and understand these features
20-
but also raises the bar for unfamiliar developers trying to add new features.
16+
loosely-coupled host functionality called
17+
[`HostComponent`](https://fermyon.github.io/rust-docs/spin/v2.2.0/spin_core/trait.HostComponent.html).
18+
As Spin has evolved, more and more runtime functionality has fallen outside of
19+
the scope of this mechanism, leading to the code for these features spreading
20+
out over the Spin codebase. This not only makes it hard to read and understand
21+
these features but also raises the bar for unfamiliar developers trying to add
22+
new features.
2123

2224
Separately, the introduction of the SpinKube project has made it clear that
2325
there will be (at least) two major embeddings of the Spin runtime environment:
@@ -28,9 +30,6 @@ of features even more important.
2830

2931
## Proposal
3032

31-
| ⚠️ NOTE: The details of this proposal are very much a work-in-progress, expected to evolve with the refactoring work intself. ⚠️ |
32-
|--|
33-
3433
The basic inversion of control approach used by `HostComponent`s will be
3534
redesigned and expanded into a new system called Spin Factors, where independent
3635
feature sets are organized into individual "factors". A "factor" encapsulates a
@@ -69,57 +68,62 @@ The overall implementation plan will be to (in parallel):
6968
## Implementation Details
7069

7170
Based on initial prototyping, the following Rust types represent the starting
72-
point for `spin-factors` (note that some type details are elided for clarity):
71+
point for `spin-factors` (simplified from the actual code for clarity):
7372

7473
```rust
7574
pub trait Factor {
76-
/// App configuration for this factor.
77-
///
78-
/// See [`Factor::configure_app`].
79-
type AppConfig;
80-
81-
/// The [`FactorInstancePreparer`] for this factor.
82-
type InstancePreparer: FactorInstancePreparer<Self>;
83-
84-
/// The per-instance state for this factor, constructed by a
85-
/// [`FactorInstancePreparer`] and available to any host-provided imports
86-
/// defined by this factor.
87-
type InstanceState;
88-
89-
/// Initializes this Factor for a runtime. This will be called at most once,
90-
/// before any call to [`FactorInstancePreparer::new`]
91-
fn init<Factors: SpinFactors>(&mut self, mut ctx: InitContext<Factors, Self>) -> Result<()> {
92-
_ = &mut ctx;
75+
// This provides a mechanism to configure this factor on a per-app basis
76+
// based on "runtime config", as currently implemented by
77+
// `spin_trigger::RuntimeConfig`.
78+
type RuntimeConfig;
79+
80+
// This stores per-app state for the factor; see `configure_app` below.
81+
// This state *may* be cached by the runtime across multiple requests.
82+
type AppState;
83+
84+
// This type is used to build per-instance (i.e. per-request) state; see
85+
// `FactorInstanceBuilder` below.
86+
type InstanceBuilder: FactorInstanceBuilder;
87+
88+
// Initializes the factor once at runtime startup. `InitContext` provides
89+
// access to the wasmtime `Linker`, so this is where any bindgen
90+
// `add_to_linker` calls go.
91+
fn init(&mut self, ctx: InitContext<Factors, Self>) -> Result<()> {
9392
Ok(())
9493
}
9594

96-
/// Performs factor-specific validation and configuration for the given
97-
/// [`App`] and [`RuntimeConfig`]. A runtime may - but is not required to -
98-
/// reuse the returned config across multiple instances. Note that this may
99-
/// be called without any call to `init` in cases where only validation is
100-
/// needed.
101-
fn configure_app<Factors: SpinFactors>(
102-
&self,
103-
app: &App,
104-
_ctx: ConfigureAppContext<Factors>,
105-
);
106-
}
95+
// This validates and uses app (manifest) and runtime configuration to build
96+
// `Self::AppState` to be used in `prepare` below.
97+
//
98+
// `ConfigureAppContext` gives access to:
99+
// - The `spin_app::App`
100+
// - This factors's `RuntimeConfig`
101+
// - The `AppState` for any factors configured before this one
102+
//
103+
// These methods can also be used on their own (without `init` or `prepare`)
104+
// to just validate app configuration for e.g. `spin doctor`.
105+
fn configure_app(&self, ctx: ConfigureAppContext) -> Result<Self::AppState>;
107106

108-
pub trait FactorInstancePreparer<Factor> {
109-
// This is the component pre-instantiation hook.
107+
// Creates a new `FactorInstanceBuilder`, which will later build per-instance
108+
// state for this factor.
109+
//
110+
// `PrepareContext` gives access to the `spin_app::AppComponent` and this
111+
// factor's `AppState`.
110112
//
111-
// The `PrepareContext` type gives access to information about the Spin app
112-
// and component being prepared and also to the Factor itself and any other
113-
// already-`prepare`d `InstancePreparer`s. The return value is the
114-
// InstancePreparer for this factor. This preparer may expose mutable state to
115-
// other factors, providing inter-factor dependency features. This takes the place
116-
// of `DynamicHostComponent::update_data`.
117-
fn new(ctx: PrepareContext) -> Result<Self>;
118-
119-
// Prepare is the component instantiation hook.
113+
// This is primary place for inter-factor dependencies to be used via the
114+
// provided `InstanceBuilders` which gives access to the `InstanceBuilder`s
115+
// of any factors prepared before this one.
116+
fn prepare(ctx: PrepareContext, builders: &mut InstanceBuilders) -> Result<Self::InstanceBuilder>;
117+
}
118+
119+
pub trait FactorInstanceBuilder {
120+
// This instance state is built per-component-instance (per-request).
120121
//
121-
// This returns the instance state for this factor. This takes the place of
122-
// `HostComponent::build_data`.
123-
fn prepare(self) -> Factor::InstanceState;
122+
// This is equivalent to the existing `HostComponent::Data` and ends up
123+
// being stored in the `wasmtime::Store`. Any `bindgen` traits for this
124+
// factor will be implemented on this type.
125+
type InstanceState;
126+
127+
fn build(self) -> Result<Self::InstanceState>;
124128
}
125129
```

0 commit comments

Comments
 (0)