Skip to content

Spin Factors SIP #2518

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 27, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 111 additions & 0 deletions docs/content/sips/0xx-spin-factors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
title = "SIP 0XX - Spin Factors"
template = "main"
date = "2024-05-20T12:00:00Z"

---

Summary: Refactor Spin Runtime Functionality with "Factors"

Owner: lann.martin@fermyon.com

Created: May 20, 2024

## Background

Spin 1.0 shipped with a mechanism for extending the runtime environment with
loosely-coupled host functionality called "host components". As Spin has
evolved, more and more runtime functionality has fallen outside of the scope of
this mechanism, leading to the code for these features spreading out over the
Spin codebase. This not only makes it hard to read and understand these features
but also raises the bar for unfamiliar developers trying to add new features.

Separately, the introduction of the SpinKube project has made it clear that
there will be (at least) two major embeddings of the Spin runtime environment:
the Spin CLI (`spin up`) and SpinKube (`containerd-shim-spin`). In order to
provide better integration into the Kubernetes ecosystem, some runtime feature
implementations will diverge between these embeddings, making the loose coupling
of features even more important.

## Proposal

The basic inversion of control approach used by `HostComponent`s will be
redesigned and expanded into a new system called Spin Factors, where independent
feature sets are organized into individual "factors". Some of the goals of this
new system:

- Expand the set integration points that a factor can use to hook into the
lifecycle of an application request. These will be driven by feature
requirements and may include e.g.:
- Runtime startup
- Application initialization
- Runtime config parsing
- Component pre-instantiation
- Component instantiation
- Cleanup (post-execution)

- Allow loosely-coupled dependencies between "factors" (features). In order to
simplify implementation and reasoning about these dependencies the dependency
graph must be acyclic.

## Implementation Plan

The overall implementation plan will be to:

1. Introduce a new `spin-factors` crate containing the basic framework.

2. Refactor existing Spin features (mostly existing `HostComponent`s) to use
this new framework.
- Framework features will be developed as needed to support this refactoring.

3. Refactor `spin-core`, `spin-trigger`, etc. to use `spin-factors`.
- Depending on subjective evaluation at this point, possibly merge
`spin-core` and `spin-factors`.

## Implementation Details
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lann how will factors receive runtime config information that is not part of a factor's runtime config but still applies to it's set up. Specifically, how should state_dir and log_dir be passed which are now set in RuntimeConfigOpts alongside provider information.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My current hypothesis is that they should be handled outside of the factors system and used to configure individual factors as needed.

state_dir will be used to build default paths for a few factors in spin up, but isn't going to be applicable to every runtime, so I think it will be up to the runtime to parse state_dir out of the runtime config and derive e.g. "default KV store path" from that to configure the KeyValueFactor.


Based on initial prototyping, the following Rust types represent the starting
point for `spin-factors` (note that some type details are elided for clarity):

```rust
pub trait Factor {
// Runtime configuration
type RuntimeConfig;
// Application-wide state; may be reused between instances
type AppState;
// Builds instance state
type InstanceBuilder: FactorInstanceBuilder;

// Init is the runtime startup lifecycle hook.
//
// The `InitContext` type here gives the factor the ability to update global
// engine configuration, most notably the `Linker`. This takes the place of
// `HostComponent::add_to_linker`.
fn init(&mut self, ctx: InitContext) -> Result<()> {
Ok(())
}

// Validates application configuration and prepares AppState.
//
// Takes the place of `DynamicHostComponent::validate_app`.
fn configure_app(&self, ctx: ConfigureAppContext) -> Result<Self::AppState>;

// Prepares InstanceState. This can access other Factors' InstanceBuilders
// to implement inter-factor dependencies.
fn prepare(
&self,
ctx: PrepareContext,
builders: &mut InstanceBuilders,
) --> Result<Self::InstanceBuilder>
}

pub trait FactorInstanceBuilder {
// Per-instance state, equivalent to `HostComponent::Data`.
type InstanceState;

// Builds the InstanceState.
//
// Takes the place of `HostComponent::build_data` and
// `DynamicHostComponent::update_data`.
fn build(self) -> Result<Self::InstanceState>;
}
```