1

I have a gRPC service written in Rust using the tonic crate. One of the methods of this service returns a stream (server-side grpc streaming) of values which are acquired by calling many devices on the network, which is why I need to rate-limit the stream. For this I'm using the governor crate - mainly because it is already in the codebase I'm working on.

use governor::state::StreamRateLimitExt;
use governor::{Quota, RateLimiter};

#[tonic::async_trait]
impl ServiceTrait for MyService {
    type ScanNetworkStream =
        Pin<Box<dyn Stream<Item = Result<ScanNetworkResponse, tonic::Status>> + Send + 'static>>;
    
    async fn scan_network(
        &self,
        _request: tonic::Request<()>,
    ) -> Result<tonic::Response<Self::ScanNetworkStream>, tonic::Status> {
        // ...
        let quota = Quota::per_second(per_second);
        let limiter = RateLimiter::direct(quota);

        let stream = futures::stream::iter(ips)
            .ratelimit_stream(&limiter)
            .map(move |ip: IpAddr| {
               // some operations on IP
            })
            // some error handling, etc.

        Ok(tonic::Response::new(Box::pin(stream)))
    }
}

This code fails to compile with an error:

328 |     ) -> Result<tonic::Response<Self::ScanNetworkStream>, tonic::Status> {
    |          --------------------------------------------------------------- type annotation requires that `limiter` is borrowed for `'static`
...
363 |             .ratelimit_stream(&limiter)
    |                               ^^^^^^^^ borrowed value does not live long enough
...
407 |     }
    |     - `limiter` dropped here while still borrowed

Is there any way to keep the limiter alive?

sveatlo
  • 543
  • 9
  • 27
  • If the stream is not async (all values are available upfront) why do you need rate limiting? – Chayim Friedman Mar 13 '23 at 07:26
  • I tried to implement that but failed. It seems to me the library does not expose enough functionality to do that ([`reference_point()`](https://docs.rs/governor/0.5.1/src/governor/state.rs.html#128-130)). [Here's the incomplete attempt](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=43a77f56a74b06d8f7f573ac48ceeaba). I'd suggest you to fill an issue, they can make the existing `RatelimitedStream` works with both borrowed and owned values via `AsRef`. – Chayim Friedman Mar 13 '23 at 08:26
  • The values available upfront are IP addresses. I need to process but not more than a **x** number per second to avoid issues with firewalls and VPNs. Thanks, I'll try to raise an issue with the crate authors. – sveatlo Mar 13 '23 at 16:18

0 Answers0