gRPC 客户端失败 "CANCELLED: io.grpc.Context was cancelled without error"
gRPC client failing with "CANCELLED: io.grpc.Context was cancelled without error"
我有一个用 C++ 编写的 gRPC 服务器和一个用 Java 编写的客户端。
使用阻塞存根一切正常。然后我决定我想将其中一个调用更改为异步调用,因此我在我的客户端中创建了一个额外的存根,这个存根是使用 newStub(channel) 而不是 newBlockingStub(channel) 创建的。我没有在服务器端做任何更改。这是一个简单的一元 RPC 调用。
所以我改变了
Empty response = blockingStub.callMethod(request);
到
asyncStub.callMethod(request, new StreamObserver<Empty>() {
@Override
public void onNext(Empty response) {
logInfo("asyncStub.callMethod.onNext");
}
@Override
public void onError(Throwable throwable) {
logError("asyncStub.callMethod.onError " + throwable.getMessage());
}
@Override
public void onCompleted() {
logInfo("asyncStub.callMethod.onCompleted");
}
});
从那时起,当我使用这个 RPC 时(大部分时间)都会调用 onError,它给出的错误是“CANCELLED:io.grpc.Context was cancelled without error”。我阅读了有关在从 RPC 调用中进行 RPC 调用时分叉 Context 对象的信息,但此处并非如此。此外,上下文似乎是服务器端对象,我看不出它与客户端有何关系。这是传播回客户端的服务器端错误吗?在服务器端,一切似乎都成功完成,所以我不知道为什么会这样。在调用 asyncStub.callMethod 后插入 1ms 睡眠似乎可以解决这个问题,但达不到目的。任何帮助理解这一点的人都将不胜感激。
一些注意事项:
- 服务器端的处理时间约为 1 微秒
- 到目前为止,阻塞调用的往返时间是几百微秒(这是我试图减少的时间,因为这本质上是一个 void 函数,所以我不需要等待一个回应)
- 这个方法连续被调用多次,以前是等上一个调用完,现在一个接一个调用。
- 原型文件中的一些片段:
service EventHandler {
rpc callMethod(Msg) returns (Empty) {}
}
message Msg {
uint64 fieldA = 1;
int32 fieldB = 2;
string fieldC = 3;
string fieldD = 4;
}
message Empty {
}
原来我错了。客户端也使用上下文对象。
解决方案是执行以下操作:
Context newContext = Context.current().fork();
Context origContext = newContext.attach();
try {
// Call async RPC here
} finally {
newContext.detach(origContext);
}
希望这对以后的其他人有所帮助。
我有一个用 C++ 编写的 gRPC 服务器和一个用 Java 编写的客户端。 使用阻塞存根一切正常。然后我决定我想将其中一个调用更改为异步调用,因此我在我的客户端中创建了一个额外的存根,这个存根是使用 newStub(channel) 而不是 newBlockingStub(channel) 创建的。我没有在服务器端做任何更改。这是一个简单的一元 RPC 调用。
所以我改变了
Empty response = blockingStub.callMethod(request);
到
asyncStub.callMethod(request, new StreamObserver<Empty>() {
@Override
public void onNext(Empty response) {
logInfo("asyncStub.callMethod.onNext");
}
@Override
public void onError(Throwable throwable) {
logError("asyncStub.callMethod.onError " + throwable.getMessage());
}
@Override
public void onCompleted() {
logInfo("asyncStub.callMethod.onCompleted");
}
});
从那时起,当我使用这个 RPC 时(大部分时间)都会调用 onError,它给出的错误是“CANCELLED:io.grpc.Context was cancelled without error”。我阅读了有关在从 RPC 调用中进行 RPC 调用时分叉 Context 对象的信息,但此处并非如此。此外,上下文似乎是服务器端对象,我看不出它与客户端有何关系。这是传播回客户端的服务器端错误吗?在服务器端,一切似乎都成功完成,所以我不知道为什么会这样。在调用 asyncStub.callMethod 后插入 1ms 睡眠似乎可以解决这个问题,但达不到目的。任何帮助理解这一点的人都将不胜感激。
一些注意事项:
- 服务器端的处理时间约为 1 微秒
- 到目前为止,阻塞调用的往返时间是几百微秒(这是我试图减少的时间,因为这本质上是一个 void 函数,所以我不需要等待一个回应)
- 这个方法连续被调用多次,以前是等上一个调用完,现在一个接一个调用。
- 原型文件中的一些片段:
service EventHandler {
rpc callMethod(Msg) returns (Empty) {}
}
message Msg {
uint64 fieldA = 1;
int32 fieldB = 2;
string fieldC = 3;
string fieldD = 4;
}
message Empty {
}
原来我错了。客户端也使用上下文对象。 解决方案是执行以下操作:
Context newContext = Context.current().fork();
Context origContext = newContext.attach();
try {
// Call async RPC here
} finally {
newContext.detach(origContext);
}
希望这对以后的其他人有所帮助。