在服务器上调用onNext时,gRPC“调用已关闭”异常

时间:2019-02-20 21:06:27

标签: java grpc grpc-java

不幸的是,这偶尔会在生产中发生,但我无法可靠地复制。

gRPC服务器向少量客户端分发较小但频繁的更新。每个客户端使用不同的参数发出同一呼叫的多个请求。这是永久性的流数据,服务器永远不会提供onComplete。

调用onNext时,出现以下错误:

Feb 20, 2019 10:13:03 AM io.grpc.internal.SerializingExecutor run
SEVERE: Exception while executing runnable concord.grpc.UncaughtExceptionServerInterceptor$SerializingServerCall$$Lambda$47/1901113624@2b4ca8e3
java.lang.IllegalStateException: call is closed
at com.google.common.base.Preconditions.checkState(Preconditions.java:174)
at io.grpc.internal.ServerCallImpl.sendMessage(ServerCallImpl.java:124)
at io.grpc.ForwardingServerCall.sendMessage(ForwardingServerCall.java:32)
at concord.grpc.UncaughtExceptionServerInterceptor$SerializingServerCall.access$1001(UncaughtExceptionServerInterceptor.java:142)
at concord.grpc.UncaughtExceptionServerInterceptor$SerializingServerCall.lambda$sendMessage$0(UncaughtExceptionServerInterceptor.java:158)
at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:123)
at com.google.common.util.concurrent.MoreExecutors$DirectExecutor.execute(MoreExecutors.java:456)
at io.grpc.internal.SerializingExecutor.schedule(SerializingExecutor.java:93)
at io.grpc.internal.SerializingExecutor.execute(SerializingExecutor.java:86)
at concord.grpc.UncaughtExceptionServerInterceptor$SerializingServerCall.sendMessage(UncaughtExceptionServerInterceptor.java:158)
at io.grpc.stub.ServerCalls$ServerCallStreamObserverImpl.onNext(ServerCalls.java:341)
at myPackage$helper.lambda$calculateChangesAndNotifyObservers$1(myCode.java:229)

根据gRPC请求保留观察者列表以订阅数据。几个客户端可能会请求完全相同的更新,因此,每个传入的客户端都会添加到列表中以获取相应的数据。

如果取消,则会通过以下方式将其从列表中删除:

if( responseObserver instanceof ServerCallStreamObserver<?> )
{
    ((ServerCallStreamObserver<?>) responseObserver).setOnCancelHandler( () ->
    {
        synchronized( _lastSnapshot )
        {
            _observers.remove( responseObserver );
        }                       
    } );
}

捕捉从onNext抛出的异常并从列表中删除客户端是否明智?还是有更好的检测方法?还是有我需要解决的潜在问题?

1 个答案:

答案 0 :(得分:1)

我今天也遇到了这个错误。 因为我在调用build()之后更改了构建器值。 错误:

SyncAepUserResponse.Builder builder = SyncAepUserResponse.newBuilder();
builder.setStatus(Status.newBuilder().setCode(200).setMessage("Successful"))
                    .setMapId(entity.getId()).build();
builder.setCode("200");
responseObserver.onNext(response);
responseObserver.onCompleted();

右:

SyncAepUserResponse.Builder builder = SyncAepUserResponse.newBuilder();
builder.setCode("200");
builder.setStatus(Status.newBuilder().setCode(200).setMessage("Successful"))
                    .setMapId(entity.getId()).build();
responseObserver.onNext(response);
responseObserver.onCompleted();