actix-web icon indicating copy to clipboard operation
actix-web copied to clipboard

Is it possible to improve the library based on gRPC protocol

Open mpv945 opened this issue 3 years ago • 6 comments

Microservices are very popular, and I hope to create an easy-to-use GRPC library to help developers transition to the rust ecosystem. Is there an example of integrating gRPC server and client at present? I am going to migrate dozens of projects to the excellent actix-web framework.

mpv945 avatar Aug 25 '22 16:08 mpv945

actix-web does not support GRPC. You can try tonic.

fakeshadow avatar Aug 25 '22 18:08 fakeshadow

Actix is an HTTP Framework, for gRPC support you can try Tonic.

If you want to create a dual server, both gRPC and HTTP, the libraries have full tokio support, so you can use tokio task using tonic and actix at the same time.

...
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    //Logger
    env_logger::init_from_env(Env::default().default_filter_or("info"));
    //Addrs
    let gaddr: SocketAddr = "0.0.0.0:50051".parse().unwrap();
    let haddr: SocketAddr = "0.0.0.0:3000".parse().unwrap();
    //gRPC Service
    let hello_service = HelloService::default();

    //Create a new server in a Tokio Task, see how it works [Spawning Tokio](https://tokio.rs/tokio/tutorial/spawning#concurrency)
    let grpc = async move {
        tokio::task::spawn(
            Server::builder()
                .add_service(HelloServer::new(hello_service))
                .serve(gaddr),
        )
    };

    //Create a new Actix Server, It already implements tokio's tasks
    let http = HttpServer::new(move || {
        App::new()
            .wrap(middleware::Logger::default())
            .service(hello_http)
    })
    .bind(haddr)?
    .run();

    println!("Listening on http://{} and http://{}", gaddr, haddr);

    //From Tokio docs about join: "Waits on multiple concurrent branches, returning when all branches complete."
    let _ret = join(grpc, http).await;

    Ok(())
}

Marlos-Rodriguez avatar Aug 28 '22 16:08 Marlos-Rodriguez

I'm currently making a library, which will codegen routing functions for actix into tonic service. It is in early stages of development, but you can follow my work here: https://github.com/blockscout/actix-prost

There is already kind-of-working routing code, so it shouldn't take too much time

leviska avatar Sep 05 '22 14:09 leviska

@Marlos-Rodriguez your code can't run, got error:

thread 'main' panicked at '`spawn_local` called from outside of a `task::LocalSet`', .cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.20.1/src/task/local.rs:314:18
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

hengfeiyang avatar Sep 16 '22 03:09 hengfeiyang

The example I did works perfectly in my system, you can see the full example here: https://github.com/Marlos-Rodriguez/rust-dual-grpc-http

I use Pop OS 22.04 LTS Nvidia and using Rust 1.63

Marlos-Rodriguez avatar Sep 16 '22 14:09 Marlos-Rodriguez

@Marlos-Rodriguez Thanks, it can work.

hengfeiyang avatar Sep 16 '22 17:09 hengfeiyang

Actix is an HTTP Framework, for gRPC support you can try Tonic.

If you want to create a dual server, both gRPC and HTTP, the libraries have full tokio support, so you can use tokio task using tonic and actix at the same time.

...
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    //Logger
    env_logger::init_from_env(Env::default().default_filter_or("info"));
    //Addrs
    let gaddr: SocketAddr = "0.0.0.0:50051".parse().unwrap();
    let haddr: SocketAddr = "0.0.0.0:3000".parse().unwrap();
    //gRPC Service
    let hello_service = HelloService::default();

    //Create a new server in a Tokio Task, see how it works [Spawning Tokio](https://tokio.rs/tokio/tutorial/spawning#concurrency)
    let grpc = async move {
        tokio::task::spawn(
            Server::builder()
                .add_service(HelloServer::new(hello_service))
                .serve(gaddr),
        )
    };

    //Create a new Actix Server, It already implements tokio's tasks
    let http = HttpServer::new(move || {
        App::new()
            .wrap(middleware::Logger::default())
            .service(hello_http)
    })
    .bind(haddr)?
    .run();

    println!("Listening on http://{} and http://{}", gaddr, haddr);

    //From Tokio docs about join: "Waits on multiple concurrent branches, returning when all branches complete."
    let _ret = join(grpc, http).await;

    Ok(())
}

I want to implement rust microservices. The internal communication of microservices adopts grpc. How do other distributed actix-web applications call the grpc service?

mpv945 avatar Oct 23 '22 06:10 mpv945