[英]gRPC Keep stream alive
I am experimenting with gRPC for long-lived streaming session as I need to guarantee message ordering from server to client.我正在尝试使用 gRPC 进行长寿命流式传输 session,因为我需要保证从服务器到客户端的消息排序。
I have the following.proto:我有以下.proto:
service Subscriber {
rpc Subscribe(SubscriptionRequest) returns (stream SubscriberEvent);
}
My current service (hosted in ASP.NET / .NET 5.0) looks like this:我当前的服务(托管在 ASP.NET / .NET 5.0 中)如下所示:
public class SubscriberService : Subscriber.SubscriberBase
{
private readonly ILogger<SubscriberService> _logger;
private readonly ConcurrentDictionary<string, IServerStreamWriter<SubscriberEvent>> _subscriptions = new();
private int _messageCount = 0;
private Timer _timer;
public SubscriberService(ILogger<SubscriberService> logger)
{
_logger = logger;
_timer = new Timer(o => TimerCallback(), null, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1));
}
private void TimerCallback()
{
Broadcast($"Current time is {DateTime.UtcNow}");
}
public override Task Subscribe(SubscriptionRequest request, IServerStreamWriter<SubscriberEvent> responseStream, ServerCallContext context)
{
_subscriptions.TryAdd(request.ClientId, responseStream);
return responseStream.WriteAsync(new SubscriberEvent() {Id = 0, Message = "Subscribe successful"});
}
public void Broadcast(string message)
{
var count = ++_messageCount;
foreach (var sub in _subscriptions.Values)
{
sub.WriteAsync(new SubscriberEvent() { Id = count, Message = message });
}
_logger.LogInformation($"Broadcast message #{count}: {message}");
}
}
My client only receives the initial 'Subscribe Successful' message, but never those triggered by the timer.我的客户只收到最初的“订阅成功”消息,但从来没有收到计时器触发的消息。 Not do I get any exceptions when calling WriteAsync.
调用 WriteAsync 时不会出现任何异常。
Am I trying to use gRPC for something it was never designed to do (a SignalR/WebSocket substitute), or am I merely missing something obvious?我是在尝试将 gRPC 用于它从未设计过的东西(SignalR/WebSocket 替代品),还是我只是错过了一些明显的东西?
For a long-running gRPC streaming, you have to wait for a client to say the connection is closed.对于长时间运行的 gRPC 流,您必须等待客户端说连接已关闭。 Something like this:
像这样的东西:
while (!context.CancellationToken.IsCancellationRequested)
{
// event-based action
responseStream.WriteAsync(new SubscriberEvent() {Id = 0, Message = "Subscribe successful"});
}
I think the previous answer is doing busy-wait.我认为前面的答案是忙等待。 So I want to show you an async version of it.
所以我想向你展示它的异步版本。
public override Task Subscribe(RequestMessage, IServerStreamWriter<ReplyMessage> responseStream, ServerCallContext context)
{
// your event-based code here
var tcs = new TaskCompletionSource();
context.CancellationToken.Register(() => tcs.TrySetCanceled(), false);
return tcs.Task;
}
BTW, I think I have been doing a project just like yours.顺便说一句,我想我一直在做一个和你一样的项目。 And I have used Observables, Subjects, and ReplaySubjects from Rx.Net .
我使用了来自 Rx.Net 的 Observables、Subjects 和ReplaySubjects 。 These are very helpful for event-based code.
这些对于基于事件的代码非常有帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.