Стриминг: server, client, bidirectional
↑ 5.2 gRPC · ← Предыдущая · → Следующая
Зачем это на собесе
Когда gRPC-стриминг оправдан и как правильно завершать поток.
Объяснение
| Вид | proto | Пример |
|---|---|---|
| Unary | rpc A (Req) returns (Res) | обычный запрос |
| Server streaming | returns (stream Res) | подписка на события, выгрузка |
| Client streaming | (stream Req) returns (Res) | загрузка файла кусками |
| Bidirectional | (stream Req) returns (stream Res) | чат, телеметрия |
// Server streaming
public override async Task Watch(WatchRequest req, IServerStreamWriter<OrderEvent> stream, ServerCallContext ctx)
{
await foreach (var e in events.SubscribeAsync(ctx.CancellationToken))
await stream.WriteAsync(new OrderEvent { Id = e.Id });
}
// Client
using var call = client.Watch(new WatchRequest());
await foreach (var e in call.ResponseStream.ReadAllAsync(ct))
Console.WriteLine(e.Id);
// Client streaming
using var upload = client.Upload();
foreach (var chunk in chunks) await upload.RequestStream.WriteAsync(chunk);
await upload.RequestStream.CompleteAsync();
var result = await upload;Нюансы и подводные камни
- Стрим держит соединение: планируйте keepalive и переподключение.
- Обрабатывайте
ctx.CancellationToken, иначе поток продолжит работать после ухода клиента. - Обратное давление: медленный клиент замедляет
WriteAsync; ограничивайте очередь. - Запись в один стрим из нескольких потоков одновременно недопустима.
- Между балансировщиками длинные стримы могут обрываться: делайте idle-timeout и retry.
Практика
- Реализуйте загрузку файла клиентским стримом по 64 КБ.
- Сделайте server streaming уведомлений с переподключением клиента.
- Соберите чат на bidirectional streaming.
Вопросы с ответами
Когда использовать streaming, а не unary?
Для больших/бесконечных потоков и событий, чтобы не буферизовать всё в одном сообщении.
Что происходит при отмене клиентом?
Срабатывает
ServerCallContext.CancellationToken; сервер должен прекратить работу.