Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Getting started

Add the dependency

cargo add velo
cargo add serde --features derive
cargo add tokio --features macros,rt-multi-thread
cargo add anyhow

The default features are http, nats-transport, grpc, and services. Add other features as you need them:

FeatureWhat it adds
services (default)Distributed events, work queues, and filesystem discovery. See Services and mux-only mode.
nats-transport (default)NATS messenger transport
grpc (default)gRPC messenger transport and gRPC frame transport
http (default)The axum dependency. The HTTP messenger transport is not built at this time.
zmqZeroMQ transport. The build compiles libzmq and needs cmake.
ucxUCX transport and RDMA rendezvous. Linux only. See Run rendezvous over RDMA.
quicQUIC transport (quinn, TLS 1.3)
nats-discoveryNATS peer and service discovery
etcdetcd peer and service discovery
nats-queueNATS JetStream work-queue backend
queue-messengerWork-queue backend on active messages
distributed-tracingOpenTelemetry trace context in message headers
simulationDiscrete-event simulation transport
test-helpersPrometheus snapshot helpers for tests

Platforms

velo builds on Linux and macOS. On macOS every feature builds except ucx. There the ucx feature compiles but adds no transport, and the ucx-rs crate builds as an empty stub, so cargo build --workspace --all-features still works. Linux sockets also set TCP_USER_TIMEOUT, which macOS does not have.

TCP is always available. UDS is always available on Unix. Filesystem discovery needs services. Discovery and queue backend features enable services too.

nats-transport, nats-discovery, and nats-queue are independent. They share the async-nats dependency, but one does not enable the others.

A first program

This program connects two instances over TCP and makes one typed request.

use std::sync::Arc;
use serde::{Deserialize, Serialize};
use velo::transports::tcp::TcpTransportBuilder;
use velo::{Handler, TypedContext, Velo};

#[derive(Serialize, Deserialize)]
struct AddRequest { a: i64, b: i64 }

#[derive(Serialize, Deserialize)]
struct AddResponse { sum: i64 }

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let node_a = Velo::builder()
        .add_transport(Arc::new(TcpTransportBuilder::new().build()?))
        .build()
        .await?;
    let node_b = Velo::builder()
        .add_transport(Arc::new(TcpTransportBuilder::new().build()?))
        .build()
        .await?;

    // Register a handler on node B.
    let handler = Handler::typed_unary_async("add", |ctx: TypedContext<AddRequest>| async move {
        Ok(AddResponse { sum: ctx.input.a + ctx.input.b })
    })
    .build();
    node_b.register_handler(handler)?;

    // Without a discovery backend, register the peer by hand.
    node_a.register_peer(node_b.peer_info())?;

    let resp: AddResponse = node_a
        .typed_unary::<AddResponse>("add")?
        .payload(&AddRequest { a: 3, b: 4 })?
        .instance(node_b.instance_id())
        .send()
        .await?;
    assert_eq!(resp.sum, 7);
    Ok(())
}

Next steps

  • Read Messaging for the four request patterns and the handler options.
  • Read Streaming to move a sequence of items between workers.
  • Read Run the examples to run the examples in the repository.