Skip to content

Add serve_grpc API #9447

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 31 commits into from
Apr 2, 2025
Merged

Add serve_grpc API #9447

merged 31 commits into from
Apr 2, 2025

Conversation

jprochazk
Copy link
Member

@jprochazk jprochazk commented Apr 1, 2025

This PR adds the serve_grpc API to all our SDKs, and the --serve-grpc option to the CLI. It can be used to spawn a gRPC server without requiring users to also spawn a Viewer.

All of this is gated behind the server feature in both the CLI and our SDKs.

Examples

Connect a native Viewer to a gRPC server hosted by the SDK

Host a gRPC server, log some data to it, and then wait for incoming connections:

Python
import time
import numpy as np
import rerun as rr

rr.init("rerun_example_serve_grpc")
rr.serve_grpc()

SIZE = 10
pos_grid = np.meshgrid(*[np.linspace(-10, 10, SIZE)] * 3)
positions = np.vstack([d.reshape(-1) for d in pos_grid]).T
col_grid = np.meshgrid(*[np.linspace(0, 255, SIZE)] * 3)
colors = np.vstack([c.reshape(-1) for c in col_grid]).astype(np.uint8).T
rr.log("my_points", rr.Points3D(positions, colors=colors, radii=0.5))

# We have to explicitly wait here, otherwise the server will shutdown immediately.
while True:
  try:
    time.sleep(1)
  except KeyboardInterrupt:
    break
C++
#include <rerun.hpp>
#include <rerun/demo_utils.hpp>
#include <thread>
#include <chrono>

using rerun::demo::grid3d;

int main() {
    // Create a new `RecordingStream` which sends data over gRPC to the viewer process.
    const auto rec = rerun::RecordingStream("rerun_example_serve_grpc_cpp");
    // Try to spawn a new viewer instance.
    rec.serve_grpc().exit_on_failure();

    // Create some data using the `grid` utility function.
    std::vector<rerun::Position3D> points = grid3d<rerun::Position3D, float>(-10.f, 10.f, 10);
    std::vector<rerun::Color> colors = grid3d<rerun::Color, uint8_t>(0, 255, 10);

    // Log the "my_points" entity with our data, using the `Points3D` archetype.
    rec.log("my_points", rerun::Points3D(points).with_colors(colors).with_radii({0.5f}));

    // We have to explicitly wait here, otherwise the server will shutdown immediately.
    while (true) {
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    }
}
Rust
use rerun::{demo_util::grid, external::glam};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let rec = rerun::RecordingStreamBuilder::new("rerun_example_serve_grpc_rs")
        .serve_grpc()?;

    let points = grid(glam::Vec3::splat(-10.0), glam::Vec3::splat(10.0), 10);
    let colors = grid(glam::Vec3::ZERO, glam::Vec3::splat(255.0), 10)
        .map(|v| rerun::Color::from_rgb(v.x as u8, v.y as u8, v.z as u8));

    rec.log(
        "my_points",
        &rerun::Points3D::new(points)
            .with_colors(colors)
            .with_radii([0.5]),
    )?;

    // We have to explicitly wait here, otherwise the server will shutdown immediately.
    loop {
        std::thread::sleep(std::time::Duration::from_secs(1));
    }
}

Then connect to the server:

rerun --connect

Connect a native Viewer to a gRPC server hosted by the CLI, with data supplied by the Python SDK

First, start the gRPC server:

rerun --serve-grpc

Then, log some data to it:

import numpy as np
import rerun as rr

rr.init("rerun_example_serve_grpc")
rr.connect_grpc()

SIZE = 10
pos_grid = np.meshgrid(*[np.linspace(-10, 10, SIZE)] * 3)
positions = np.vstack([d.reshape(-1) for d in pos_grid]).T
col_grid = np.meshgrid(*[np.linspace(0, 255, SIZE)] * 3)
colors = np.vstack([c.reshape(-1) for c in col_grid]).astype(np.uint8).T
rr.log("my_points", rr.Points3D(positions, colors=colors, radii=0.5))

Finally, connect to the server from a native Viewer:

rerun --connect

Copy link

github-actions bot commented Apr 1, 2025

Web viewer built successfully. If applicable, you should also test it:

  • I have tested the web viewer
Result Commit Link Manifest
a293330 https://rerun.io/viewer/pr/9447 +nightly +main

Note: This comment is updated whenever you push a commit.

Copy link

github-actions bot commented Apr 1, 2025

Latest documentation preview deployed successfully.

Result Commit Link
a293330 https://landing-phta6aga7-rerun.vercel.app/docs

Note: This comment is updated whenever you push a commit.

@jprochazk jprochazk added include in changelog 🪵 Log & send APIs Affects the user-facing API for all languages labels Apr 1, 2025
@jprochazk jprochazk force-pushed the jan/spawn-headless branch from fe08458 to cdf7c88 Compare April 2, 2025 11:28
@jprochazk jprochazk marked this pull request as ready for review April 2, 2025 12:34
@jprochazk jprochazk added the CLI Related to the Rerun CLI label Apr 2, 2025
@emilk emilk self-requested a review April 2, 2025 14:46
@emilk
Copy link
Member

emilk commented Apr 2, 2025

> rerun --serve-grpc
[… INFO  re_grpc_server] Listening for gRPC connections on 0.0.0.0:9876

> rerun --connect 0.0.0.0:9876
Error: invalid or missing scheme (expected `rerun(+http|+https)://`)

Let's improve the first message to

Listening for gRPC connections on 0.0.0.0:9876. You can connect to this server by running rerun --connect rerun+http://0.0.0.0:9876/proxy

The second error message could also be improved with:

…expected one of: rerun:// rerun+http:// rerun+https://


> rerun --connect rerun://0.0.0.0:9876/proxy
[… WARN  re_viewer::app] Data source rerun://0.0.0.0:9876/proxy has left unexpectedly: transport error

We should be able to improve this error message too, and hint about what went wrong.

What more common mistakes could the user do, and how can we help them in those situations?

builder.enable_all();
let rt = builder.build().expect("failed to build tokio runtime");

rt.block_on(re_grpc_server::serve_from_channel(
Copy link
Member

Choose a reason for hiding this comment

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

Will this work even if the user already has #[tokio::main] on their fn main?

Copy link
Member Author

@jprochazk jprochazk Apr 2, 2025

Choose a reason for hiding this comment

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

Yes, we're spawning a new thread and using a single-threaded runtime, so anything goes.

@jprochazk
Copy link
Member Author

jprochazk commented Apr 2, 2025

rerun --connect rerun://0.0.0.0:9876/proxy
[… WARN re_viewer::app] Data source rerun://0.0.0.0:9876/proxy has left unexpectedly: transport error

We should be able to improve this error message too, and hint about what went wrong.

We have no idea. tonic doesn't expose any concrete information about what went wrong, their error is a wrapper over Box<dyn std::error::Error>. They don't even expose the kind on tonic::transport::Error, so we can't even know for sure if what failed is related to forming a connection. It could literally be anything 🤷. All we can say for sure is that the connect call failed.

Copy link
Member

@emilk emilk left a comment

Choose a reason for hiding this comment

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

Nice

Comment on lines +76 to +81
let connect_addr = if addr.ip().is_loopback() || addr.ip().is_unspecified() {
format!("rerun+http://127.0.0.1:{}/proxy", addr.port())
} else {
format!("rerun+http://{addr}/proxy")
};
re_log::info!("Listening for gRPC connections on {addr}. Connect by running `rerun --connect {connect_addr}`");
Copy link
Member

Choose a reason for hiding this comment

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

very nice

@jprochazk jprochazk merged commit 68e8f28 into main Apr 2, 2025
42 checks passed
@jprochazk jprochazk deleted the jan/spawn-headless branch April 2, 2025 19:39
@emilk emilk mentioned this pull request Apr 11, 2025
16 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLI Related to the Rerun CLI include in changelog 🪵 Log & send APIs Affects the user-facing API for all languages
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Provide API to spawn a gRPC server
3 participants