Components
WebAssembly componentsβ
WebAssembly components are the unit of compute for wasmCloud. The Component Model provides a standard for creating portable, interoperable, and composable code with WebAssembly. This aligns well with wasmCloud's approach to building distributed applications that are composable and interface-driven, and we are committed to supporting a componentized ecosystem.
The wasmCloud host remains up-to-date with the latest versions of wasmtime and WASI Preview 2, a set of standard APIs designed to allow WebAssembly components to access external resources in a safe and portable way.
Components in wasmCloudβ
In wasmCloud, applications are comprised of components and providers that communicate with one another via interfaces.
- Components: Core logic that runs statelessly (ex. API for a web app).
- Providers: Longer-lived processes fulfilling non-functional requirements (ex. Key-value storage).
In wasmCloud usage and documentation, the term "component" is conventionally used to refer to a component implementing stateless core logicβwe will also use the term application component for this purpose. For example, the wash new component
command creates a new application component.
Providers are implemented as executable host plugins. For clarity, we will always use the terms "provider" or "capability provider" in usage and documentation. You can read more about providers on the provider page.
Application componentsβ
An application component is the smallest unit of deployable, portable compute within the wasmCloud ecosystem. Application components can handle messages delivered to them by the host runtime and can invoke functions on capability providers.
wasmCloud application components are:
Statelessβ
When an application component needs state, it uses a capability provider. Leaving state to capability providers enables wasmCloud to orchestrate invocations in complex applications without regard to specific instances of application components or where they're running.
Secureβ
Application components are secure by default. Because WebAssembly components that can't use WASI capabilities directly, they are incapable of interacting with any operating system functionality on their own. The only way application components can affect their external environment is through the use of a capability provider. The host runtime will only allow calls between linked components and providers.
Flat in hierarchyβ
In a zero trust environment, allowing application components to spawn others is a security risk. wasmCloud hosts maintain the horizontal scale of application components with an entirely flat hierarchy.
Internally single-threadedβ
The surrounding environment of the host runtime may have varying levels of concurrency support. This support may differ depending on whether the host is running in a browser, on a constrained device, or in a VM somewhere. However, the code for application components should be independent of these conditions and never have to change, even if the surrounding environment adopts a different concurrency model.
While it's nice not worrying about the underlying concurrency model, it's important to understand that single-threaded code has the potential to create bottlenecks. Therefore, when developing message handlers for actor components, embrace the design of performing small amounts of work in a "get in and get out fast" approach. Divide the work into the smallest bits possible, and perform each bit as fast as possible. This approach maximizes the benefits of external concurrency while still keeping the code simple and synchronous.
Reactiveβ
Reactive: An application component can't start any flow on its own. Components can only react to outside stimuli in the form of messages delivered by the host. Developers declare which messages their actor components handle as input and return messages as output. The following example implements a handler that receives a bank account query and responds with the bank account value:
#[async_trait]
impl BankServer for BankComponent {
async fn handle_inquiry(&self,
ctx: &Context,
query: &BalanceInquiry) -> RpcResult<Balance> {
// queried using another capability provider
let balance = get_balance()?;
Ok(Balance{
account: query.account,
balance
})
}
}
The preceding component code could communicate with capability providers (for example, a key-value store to retrieve the account balance), but only in response to a message from the host.
Connected by abstractionsβ
wasmCloud components are loosely coupled with the providers they use for non-functional requirements. A component doesn't communicate with Redis or Cassandra or Consul; instead it communicates with a generalized abstraction over the keyvalue
interface.
An interface represents an abstracted functionality. As long as the provider implements the correct interface, it's considered compatible with your component. A component written using the keyvalue
interface should be able to work with any key-value store. This decoupling also enables swapping the store at runtime without requiring a rebuild or redeploy. Learn more about wasmCloud's interface support on the Interface page.
Keep readingβ
Continue to learn more about providers, or...
- Build and deploy a component in the Quickstart.
- Dig deeper on creating components in the Developer Guide.