@@ -13,11 +13,13 @@ Created: May 20, 2024
13
13
## Background
14
14
15
15
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.
21
23
22
24
Separately, the introduction of the SpinKube project has made it clear that
23
25
there will be (at least) two major embeddings of the Spin runtime environment:
@@ -28,9 +30,6 @@ of features even more important.
28
30
29
31
## Proposal
30
32
31
- | ⚠️ NOTE: The details of this proposal are very much a work-in-progress, expected to evolve with the refactoring work intself. ⚠️ |
32
- | --|
33
-
34
33
The basic inversion of control approach used by ` HostComponent ` s will be
35
34
redesigned and expanded into a new system called Spin Factors, where independent
36
35
feature sets are organized into individual "factors". A "factor" encapsulates a
@@ -69,57 +68,62 @@ The overall implementation plan will be to (in parallel):
69
68
## Implementation Details
70
69
71
70
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):
73
72
74
73
``` rust
75
74
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 <()> {
93
92
Ok (())
94
93
}
95
94
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 >;
107
106
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`.
110
112
//
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).
120
121
//
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 >;
124
128
}
125
129
```
0 commit comments