Welcome to the new Golem Cloud Docs! 👋
Documentation
Rpc

Worker to Worker communication

Concept

Golem allows creating and invoking workers through its REST API or command-line interface, using the rules defined on the component interface page. These methods are for working with Golem workers from the outside world. However, the public API for calling one worker from another is not very convenient.

Golem instead introduces a new way to do worker-to-worker communication, using a method called WASM RPC. This consists of the following building blocks:

  • Golem provides a host resource for workers, which can be imported into any Golem project and used to invoke a remote worker by passing the target worker, the name of the invoked function and its parameters in a dynamic way using a data type called wit-value.
  • A CLI tool called wasm-rpc-stubgen can take any Golem worker, and generate a pair of a WIT definition and a WASM component implementing a "stub" for remotely calling that given worker. The generated stub internally uses the above mentioned low-level invocation API, providing a typed interface for working with a remote Golem worker.
  • The generated stub can be composed with other Golem workers using standard WASM tooling to get a resulting WASM ready to be uploaded as a Golem component, capable of typed worker-to-worker communication.

Details

Low-level interface

The low-level host interface this technique uses is defined in wasm-rpc.wit (opens in a new tab) as the following:

package golem:rpc@0.1.0;
 
interface types {
  use wasi:io/poll@0.2.0.{pollable};
 
  type node-index = s32;
 
  record wit-value {
    nodes: list<wit-node>,
  }
 
  variant wit-node {
    record-value(list<node-index>),
    variant-value(tuple<u32, option<node-index>>),
    enum-value(u32),
    flags-value(list<bool>),
    tuple-value(list<node-index>),
    list-value(list<node-index>),
    option-value(option<node-index>),
    result-value(result<option<node-index>, option<node-index>>),
    prim-u8(u8),
    prim-u16(u16),
    prim-u32(u32),
    prim-u64(u64),
    prim-s8(s8),
    prim-s16(s16),
    prim-s32(s32),
    prim-s64(s64),
    prim-float32(float32),
    prim-float64(float64),
    prim-char(char),
    prim-bool(bool),
    prim-string(string),
  }
 
  record uri {
    value: string,
  }
 
  variant rpc-error {
    protocol-error(string),
    denied(string),
    not-found(string),
    remote-internal-error(string)
  }
 
  resource wasm-rpc {
    constructor(location: uri);
 
    invoke-and-await: func(function-name: string, function-params: list<wit-value>) -> result<wit-value, rpc-error>;
 
    invoke: func(function-name: string, function-params: list<wit-value>) -> result<_, rpc-error>;
 
    async-invoke-and-await: func(function-name: string, function-params: list<wit-value>) -> future-invoke-result;
  }
}
 
world wit-value {
    import types;
}

Worker URI

The worker URI that has to be passed to the remote interface as a parameter identifies a specific Golem worker, consisting of the component ID and the worker name. It can be constructed by hand using the pattern worker://component-id/worker-name, and a running worker can get its own URI using the Golem-specific host function golem:api/host.{get-self-uri}.

Stub generator

The latest version of golem-cli and golem-cloud-cli contains a stubgen subcommand which implements a set of tools to generate and integrate WASM RPC stubs:

WASM RPC stub generator

Usage: golem-cli stubgen [OPTIONS] <COMMAND>

Commands:
  generate              Generate a Rust RPC stub crate for a WASM component
  build                 Build an RPC stub for a WASM component
  add-stub-dependency   Adds a generated stub as a dependency to another WASM component
  compose               Compose a WASM component with a generated stub WASM
  initialize-workspace  Initializes a Golem-specific cargo-make configuration in a Cargo workspace for automatically generating stubs and composing results
  help                  Print this message or the help of the given subcommand(s)

Options:
  -v, --verbose...  Increase logging verbosity
  -q, --quiet...    Decrease logging verbosity
  -h, --help        Print help

stubgen generate

Generate a Rust RPC stub crate for a WASM component
 
Usage: golem-cli stubgen generate [OPTIONS] --source-wit-root <SOURCE_WIT_ROOT> --dest-crate-root <DEST_CRATE_ROOT>
 
Options:
  -s, --source-wit-root <SOURCE_WIT_ROOT>
          The root directory of the component's WIT definition to be called via RPC
  -d, --dest-crate-root <DEST_CRATE_ROOT>
          The target path to generate a new stub crate to
  -w, --world <WORLD>
          The world name to be used in the generated stub crate. If there is only a single world in the source root package, no need to specify
      --stub-crate-version <STUB_CRATE_VERSION>
          The crate version of the generated stub crate [default: 0.0.1]
      --wasm-rpc-path-override <WASM_RPC_PATH_OVERRIDE>
          The path to the `wasm-rpc` crate to be used in the generated stub crate. If not specified, the latest version of `wasm-rpc` will be used

The parameters have the following meaning:

  • --source-wit-root must point to the directory of the WIT specification of the worker to be called remotely. This is usually a wit subdirectory in the worker's component's source code.
  • --dest-crate-root is a new directory where the generated RPC stub will be put. The tool's current version does not generate a WASM file directly, instead it outputs a complete Rust crate which can be compiled via cargo component build (as described on the Rust page) or included in a Rust workspace.
  • --world can be used to select the exported world from the source WIT, if there are more than one. If there is only one world defined, there is no need to use this parameter.
  • --stub-crate-version sets the generated Rust crate's version to the given value.
  • --wasm-rpc-path-override is useful when working on the wasm-rpc crate itself, to point the dependency to a local path instead of using the published version.

The generated crate will contain a new WIT file - named wit/_stub.wit - which contains all the exported functions, interfaces and resources from the source worker's WIT specification, but each of them is packaged into an exported resource representing the remote connection to a specific remote worker. The generated Rust code implements these exported resources using the low-level invocation interface defined above.

For example if the original worker's WIT exported an interface and a resource through a function:

package golem:component;
 
interface api {
  resource counter {
    constructor(name: string);
    inc-by: func(value: u64);
    get-value: func() -> u64;
 
    merge-counters: static func(counter1: counter, counter2: counter, name: string) -> counter;
  }
 
  get-all-counters: func() -> list<counter>;
}
 
world my-world {
  export api;
}

The generated stub WIT specification for the above interface will be:

package golem:component-stub;
 
interface stub-my-world {
  use golem:rpc/types@0.1.0.{uri};
 
  resource api {
    constructor(location: uri);
    get-all-counters: func() -> list<counter>;
  }
 
  resource counter {
    constructor(location: uri, name: string);
    inc-by: func(value: u64);
    get-value: func() -> u64;
    merge-counters: static func(counter1: counter, counter2: counter, name: string) -> counter;
  }
 
}
 
world wasm-rpc-stub-my-world {
  export stub-my-world;
}

Each exported interface and resource becomes a new resource, accepting a remote worker URI as a parameter.

stubgen build

Build an RPC stub for a WASM component
 
Usage: golem-cli stubgen build [OPTIONS] --source-wit-root <SOURCE_WIT_ROOT> --dest-wasm <DEST_WASM> --dest-wit-root <DEST_WIT_ROOT>
 
Options:
  -s, --source-wit-root <SOURCE_WIT_ROOT>
          The root directory of the component's WIT definition to be called via RPC
      --dest-wasm <DEST_WASM>
          The name of the stub WASM file to be generated
      --dest-wit-root <DEST_WIT_ROOT>
          The directory name where the generated WIT files should be placed
  -w, --world <WORLD>
          The world name to be used in the generated stub crate. If there is only a single world in the source root package, no need to specify
      --stub-crate-version <STUB_CRATE_VERSION>
          The crate version of the generated stub crate [default: 0.0.1]
      --wasm-rpc-path-override <WASM_RPC_PATH_OVERRIDE>
          The path to the `wasm-rpc` crate to be used in the generated stub crate. If not specified, the latest version of `wasm-rpc` will be used. It needs to be an **absolute path**

Similar to the stubgen generate subcommand, but instead of generating the source code for a Rust crate, it builds the stub WASM directly.

The parameters have the following meaning:

  • --source-wit-root must point to the directory of the WIT specification of the worker to be called remotely. This is usually a wit subdirectory in the worker's component's source code.
  • --dest-wasm is the target WASM file to be generated.
  • --dest-wit-root is the target directory where the stub's WIT file and its dependencies will be generated into.
  • --world can be used to select the exported world from the source WIT, if there are more than one. If there is only one world defined, there is no need to use this parameter.
  • --stub-crate-version sets the generated Rust crate's version to the given value.
  • --wasm-rpc-path-override is useful when working on the wasm-rpc crate itself, to point the dependency to a local path instead of using the published version. It must be an absolute path.

See the stubgen generate command's description above for more details about the generated WIT interface.

stubgen add-stub-dependency

Adds a generated stub as a dependency to another WASM component
 
Usage: golem-cli stubgen add-stub-dependency [OPTIONS] --stub-wit-root <STUB_WIT_ROOT> --dest-wit-root <DEST_WIT_ROOT>
 
Options:
  -s, --stub-wit-root <STUB_WIT_ROOT>  The WIT root generated by either `generate` or `build` command
  -d, --dest-wit-root <DEST_WIT_ROOT>  The WIT root of the component where the stub should be added as a dependency
  -o, --overwrite                      This command would not do anything if it detects that it would change an existing WIT file's contents at the destination. With this flag, it can be forced to overwrite those files
  -u, --update-cargo-toml              Enables updating the Cargo.toml file in the parent directory of `dest-wit-root` with the copied dependencies

This is a follow-up step after generating (and/or building) the RPC stub. It takes the generated stub's WIT specification and integrates it into another project's WIT specification as a dependency, so that other project can use the stub interface for the remote procedure call.

The parameters have the following meaning:

  • --stub-wit-root must point to the directory of the WIT specification of the generated stub. This is the wit directory in the output of stubgen generate or the directory passed by --dest-wit-root to stubgen build.
  • --dest-wit-root is the wit directory of the Golem project that will use the generated stub for remote worker calls.
  • --overwrite is an optional flag to force overwriting the destination WIT files if they already exist.
  • --update-cargo-toml is an optional flag to update the Cargo.toml file in the parent directory of dest-wit-root with the copied dependencies. While the command in general works with any guest language, this extra flag enables support for Rust projects built by cargo-component where the dependencies are listed in the Cargo.toml file.

stubgen compose

Compose a WASM component with a generated stub WASM
 
Usage: golem-cli stubgen compose [OPTIONS] --source-wasm <SOURCE_WASM> --stub-wasm <STUB_WASM> --dest-wasm <DEST_WASM>
 
Options:
      --source-wasm <SOURCE_WASM>  The WASM file of the caller component
      --stub-wasm <STUB_WASM>      The WASM file of the generated stub. Multiple stubs can be listed
      --dest-wasm <DEST_WASM>      The name of the composed WASM file to be generated

The compose subcommand is an alternative for using the general purpose wasm-tools compose command providing a simpler way to compose the generated RPC stubs with the compiled WASM components using these stubs.

Compiling a project that uses a stub as a dependency cannot be directly uploaded to Golem, as its stub dependencies will not be satisfied by the Golem worker executor. It first has to be composed with the compiled stub WASMs. This is the last step to be performed before uploading the WASM to Golem.

The parameters have the following meaning:

  • --source-wasm is the WASM file of the caller component (the one depending on the stub).
  • --stub-wasm is the WASM file of the generated stub. Multiple stubs can be listed.
  • --dest-wasm is the target WASM file to be generated. This is the file that can be uploaded to Golem.

stubgen initialize-workspace

Initializes a Golem-specific cargo-make configuration in a Cargo workspace for automatically generating stubs and composing results
 
Usage: golem-cli stubgen initialize-workspace [OPTIONS] --targets <TARGETS> --callers <CALLERS>
 
Options:
      --targets <TARGETS>
          List of subprojects to be called via RPC
      --callers <CALLERS>
          List of subprojects using the generated stubs for calling remote workers
      --wasm-rpc-path-override <WASM_RPC_PATH_OVERRIDE>
          The path to the `wasm-rpc` crate to be used in the generated stub crate. If not specified, the latest version of `wasm-rpc` will be used

If all the workers involved in worker to worker communication have their source code in a single cargo workspace, then this command can be used to add a cargo-make (opens in a new tab) build specification that performs all the above steps automatically when building the workspace with cargo make build-flow or cargo make release-build-flow.

The parameters have the following meaning:

  • --targets is a list of subprojects to be called via RPC. These are the projects that the tool will generate stubs for.
  • --callers is a list of subprojects using (any of) the generated stubs for calling remote workers.
  • --wasm-rpc-path-override is useful when working on the wasm-rpc crate itself, to point the dependency to a local path instead of using the published version. It must be an absolute path.

The initialize-workspace command is supposed to be used only once in a workspace. After it succeeds, cargo make build-flow and cargo make release-build-flow can be used to build the workspace, and the generated stubs will be automatically added as dependencies to the caller projects and the compiled WASM files will be composed with the stubs.

Example

Please read the worker to worker communication blog post (opens in a new tab) for a full example of how to use the stub generator calling one worker from another.