【发布时间】:2022-06-18 01:22:28
【问题描述】:
Grpc.Core 2.38.0
我有一组使用 grpc 流参与进程间通信的应用程序。我们不时注意到服务器进程中的锁定和内存耗尽(由于锁定)无法完成对IAsyncStreamWriter.WriteAsync(...)的调用
最近对 grpc (.net) 的更改已将 WriteAsync API 更改为接受 CancellationToken,但 Grpc.Core 包中不提供此功能。
【问题讨论】:
Grpc.Core 2.38.0
我有一组使用 grpc 流参与进程间通信的应用程序。我们不时注意到服务器进程中的锁定和内存耗尽(由于锁定)无法完成对IAsyncStreamWriter.WriteAsync(...)的调用
最近对 grpc (.net) 的更改已将 WriteAsync API 更改为接受 CancellationToken,但 Grpc.Core 包中不提供此功能。
【问题讨论】:
接受流的配置错误的 grpc 客户端可能会导致死锁。如果客户端在错误处理期间不处理AsyncServerStreamingCall,则会在服务器上发生死锁。
例子:
async Task ClientStreamingThread()
{
while (...)
{
var theStream = grpcService.SomeStream(new());
try
{
while (await theStream.ResponseStream.MoveNext(shutdownToken.Token))
{
var theData = theStream.ResponseStream.Current;
}
}
catch (RpcException)
{
// if an exception occurs, start over, reopen the stream
}
}
}
上面的示例包含行为不端的客户端。如果出现RpcException,我们将返回到while 循环的开头并打开另一个流而不清理前一个流。这会导致死锁。
通过处理前一个流来“修复”客户端代码,如下所示:
async Task ClientStreamingThread()
{
while (...)
{
// important. dispose of theStream if it goes out of scope
using var theStream = grpcService.SomeStream(new());
try
{
while (await theStream.ResponseStream.MoveNext(shutdownToken.Token))
{
var theData = theStream.ResponseStream.Current;
}
}
catch (RpcException)
{
// if an exception occurs, start over, reopen the stream
}
}
}
【讨论】: