Skip to main content
Version: 1.0

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.

Note

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:

rust
#[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...