actix / actix-web

Actix Web is a powerful, pragmatic, and extremely fast web framework for Rust.
https://actix.rs
Apache License 2.0
21.72k stars 1.68k forks source link

Is it possible to improve the library based on gRPC protocol #2853

Open mpv945 opened 2 years ago

mpv945 commented 2 years ago

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.

fakeshadow commented 2 years ago

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

Marlos-Rodriguez commented 2 years ago

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(())
}
leviska commented 2 years ago

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

hengfeiyang commented 2 years ago

@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
Marlos-Rodriguez commented 2 years ago

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

hengfeiyang commented 2 years ago

@Marlos-Rodriguez Thanks, it can work.

mpv945 commented 2 years ago

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?