Tradias / asio-grpc

Asynchronous gRPC with Asio/unified executors
https://tradias.github.io/asio-grpc/
Apache License 2.0
357 stars 34 forks source link

[Question]: Slowly receiveing client in long-lived streaming #94

Closed Marwin34 closed 6 days ago

Marwin34 commented 8 months ago

Hi Tradias,

Is there a way to detect a slowly receiving client in a long-lived streaming RPC in asio-grpc (or grpc itself)? I am working on a server application that sends data to clients using streaming RPCS, and I would like to detect slowly receiving clients and then drop the connection with them since it can lead to queuing up data on sockets, potentially resulting in slowing down the server or ooming it. Could such a mechanism be implemented with asio-grpc?

Thanks in advance.

Tradias commented 8 months ago

Asio-grpc just acts as a small wrapper around gRPC's API. In the case of a client-streaming RPC, for example, that would be grpc::ServerAsyncWriter::Write. If that call really completes slowly for slow clients (I haven't tested it, also note this set_write_through option), then you can use it to automatically drop the connection like so:

const auto slow_threshold = std::chrono::seconds(5);
agrpc::Alarm alarm{grpc_context};
auto [completion_order, alarm_ok, write_ok] =
    co_await asio::experimental::make_parallel_group(
        alarm.wait(std::chrono::system_clock::now() + slow_threshold, asio::deferred),
        rpc.write(response, asio::deferred))
        .async_wait(asio::experimental::wait_for_one{}, asio::use_awaitable);
if (!write_ok)
{
    // client dropped connection or was slow (alarm finished and caused cancellation of rpc with invokes grpc::ServerContext::TryCancel)
    co_return;
}
nqf commented 3 weeks ago

How to call set_write_through in asio-grpc ?

Tradias commented 3 weeks ago

@nqf ServerRPC::write, ServerRPC::write_and_finish and ClientRPC::write all take an optional second argument: grpc::WriteOptions. Which means you can do:

rpc.write(request, grpc::WriteOptions().set_write_through(), <completion token>);
nqf commented 3 weeks ago
rpc.write(request, grpc::WriteOptions().set_write_through(), <completion token>);

Is it possible for rpc.write to throw an exception? As far as I know, ASIO can throw exceptions or return error codes

Tradias commented 3 weeks ago

No, since gRPC never throws exceptions I am not inventing any either. The completion signature of rpc.write is void(bool) which differs from the typical asio completion signatures void(error_code, <something>). Only if the first argument is an error_code will asio automatically convert it to an exception.

From the asio-grpc documentation:

The completion signature is void(bool). true means that the data/metadata/status/etc is going to go to the wire. If it is false, it is not going to the wire because the call is already dead (i.e., canceled, deadline expired, other side dropped the channel, etc).

nqf commented 3 weeks ago

No, since gRPC never throws exceptions I am not inventing any either. The completion signature of rpc.write is void(bool) which differs from the typical asio completion signatures void(error_code, <something>). Only if the first argument is an error_code will asio automatically convert it to an exception.

From the asio-grpc documentation:

The completion signature is void(bool). true means that the data/metadata/status/etc is going to go to the wire. If it is false, it is not going to the wire because the call is already dead (i.e., canceled, deadline expired, other side dropped the channel, etc).

thanks

Tradias commented 6 days ago

@nqf Does this answer the op's question? Aka. can this issue be closed now?

nqf commented 6 days ago

@nqf Does this answer the op's question? Aka. can this issue be closed now?

I have no more questions,I think you can close it