简体   繁体   English

gRPC 保持 stream 存活

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM