简体   繁体   English

JAVA GRPC 双向 Stream 抛出 CANCELLED: io.grpc.Context 已取消且没有错误

[英]JAVA GRPC Bi-directional Stream throws CANCELLED: io.grpc.Context was cancelled without error

I am trying to implement a bi-directional streaming service for all nodes in a cluster.我正在尝试为集群中的所有节点实现双向流服务。 Using this, these nodes are supposed to sync their states ie whenever any server would get any update using serveRequest request from any client, it would pass that information to other nodes in the cluster using streaming service syncState .使用这个,这些节点应该同步它们的状态,即每当任何服务器使用来自任何客户端的serveRequest请求获得任何更新时,它都会使用流服务syncState状态将该信息传递给集群中的其他节点。

For this, every node in the cluster has clients set up to connect to every other node.为此,集群中的每个节点都设置了客户端以连接到每个其他节点。 Clients initialization is one-time and a stream is set up (1 client has 1 stream per node) using which it is supposed to sync the latest state to other nodes.客户端初始化是一次性的,并且设置了 stream(1 个客户端每个节点有 1 个 stream),它应该使用它来将最新的 state 同步到其他节点。

Sample Proto样品原型

message MessageRequest {
  string policyId = 1;
  string txnId = 2;
  string clientId = 3;
}

message Acknowledgement {
  string serverId = 1;
  string txnId = 2;
}

service SyncState{
  rpc sync(stream MessageRequest) returns (stream Acknowledgement) {}
}

service ServeRequest{
  rpc newRequest(MessageRequest) returns (Acknowledgement) {}
}

SyncService同步服务

public class SyncStateService extends SyncStateServiceGrpc.SyncStateServiceImplBase {

    private static final Logger logger = LoggerFactory.getLogger(SyncStateService.class);
    private SyncManager manager;
    private Configuration config;

    public SyncStateService(SyncManager manager, Configuration config) {
        this.manager = manager;
        this.config = config;
    }

    @Override
    public StreamObserver<MessageRequest> sync(StreamObserver<Acknowledgement> responseObserver) {
        logger.info("Server received connection request");
        return new StreamObserver<MessageRequest>() {
            @Override
            public void onNext(MessageRequest request) {
                Acknowledgement ack = Acknowledgement.newBuilder().setTxnId(request.getTxnId()).setServerId(config.getClientId()).build();
                MessageRequest clone = MessageRequest.newBuilder().setClientId(config.getClientId()).setTxnId(request.getTxnId()).build();
                CompletableFuture.runAsync(() -> manager.sendMessage(clone));
                responseObserver.onNext(ack);
            }

            @Override
            public void onError(Throwable t) {
                logger.error("Error on server for client stream", t);
            }

            @Override
            public void onCompleted() {
                logger.info("client called on completed on stream, server closes response stream");
                responseObserver.onCompleted();
            }
        };
    }
}

Client Stream Manager客户 Stream 经理

public class SyncManager {
    private Map<String, SyncClient> client = new HashMap<>();
    private final Configuration  config;

    public SyncManager(Configuration  config) {
        this.config = config;
    }

    public void startStateSync(MessageRequest clone) {
        //This method is called whenever
        //ServeRequest APi is hit on any server
        config.getNodes().forEach(e->{
            SyncClient syncClient = client.get(e);
            if (syncClient== null){
                syncClient = new SyncClient(e);
            }
            MessageRequest gossipRequest = MessageRequest.newBuilder().setTxnId(clone.getTxnId())
                    .setPolicyId(clone.getPolicyId()).setClientId(config.getClientId()).build();
            syncClient.syncMessage(e, gossipRequest);
        });
    }

    public void sendMessage(MessageRequest clone) {
        // Server which has received state sync request
        //forwards the same info to other servers
        config.getNodes().forEach(e->{
            SyncClient syncClient = client.get(e);
            if (syncClient== null){
                syncClient = new SyncClient(e);
            }
            MessageRequest gossipRequest = MessageRequest.newBuilder().setTxnId(clone.getTxnId())
                    .setPolicyId(clone.getPolicyId()).setClientId(config.getClientId()).build();
            syncClient.syncMessage(e, gossipRequest);
        });
    }
}

Client:客户:

public class SyncClient {
    private static final Logger logger = LoggerFactory.getLogger(SyncClient.class);
    private final ManagedChannel channel;
    private final SyncStateServiceGrpc.SyncStateServiceStub stub;
    private final StreamObserver<MessageRequest> stream;

    public SyncClient(String node) {
        channel = ManagedChannelBuilder.forTarget(node)
                .usePlaintext()
                .keepAliveTime(new Long(2), TimeUnit.DAYS)
                .keepAliveTimeout(new Long(1), TimeUnit.DAYS)
                .keepAliveWithoutCalls(true)
                .build();
        stub = SyncStateServiceGrpc.newStub(channel);
        stream = getStreamObserver();
    }

    private StreamObserver<MessageRequest> getStreamObserver() {
        final StreamObserver<MessageRequest> stream;
        stream = stub.sync(new StreamObserver<>() {
            @Override
            public void onNext(Acknowledgement value) {
                String txnId = value.getTxnId();
                logger.info("Received message from server");
                String serverId = value.getServerId();

            }

            @Override
            public void onError(Throwable t) {
                logger.error("Error occurred", t);
            }

            @Override
            public void onCompleted() {
                logger.info("Completed");
            }
        });
        return stream;
    }
    
    public void syncMessage(String node, MessageRequest request) {
        logger.info("Sending message to:: {}", node);
        stream.onNext(request);
    }
}

Issues:问题:

  1. Whenever a client is setup, the server's sync method is never triggered(No logs on server, must be printed this Server received connection request )每当设置客户端时,从不触发服务器的同步方法(服务器上没有日志,必须打印此服务器收到的连接请求
  2. stream.onNext(request) on clients always throws error:客户端上的stream.onNext(request)总是抛出错误:

io.grpc.StatusRuntimeException: CANCELLED: io.grpc.Context was cancelled without error at io.grpc.Status.asRuntimeException(Status.java:535) ~[grpc-api-1.36.0.jar:1.36.0] at io.grpc.stub.ClientCalls$StreamObserverToCallListenerAdapter.onClose(ClientCalls.java:478) ~[grpc-stub-1.36.0.jar:1.36.0] at io.grpc.internal.DelayedClientCall$DelayedListener$3.run(DelayedClientCall.java:464) ~[grpc-core-1.36.0.jar:1.36.0] at io.grpc.internal.DelayedClientCall$DelayedListener.delayOrExecute(DelayedClientCall.java:428) ~[grpc-core-1.36.0.jar:1.36.0] at ZF98ED07A4D5F50F7D io.grpc.StatusRuntimeException: CANCELLED: io.grpc.Context was cancelled without error at io.grpc.Status.asRuntimeException(Status.java:535) ~[grpc-api-1.36.0.jar:1.36.0] at io .grpc.stub.ClientCalls$StreamObserverToCallListenerAdapter.onClose(ClientCalls.java:478) ~[grpc-stub-1.36.0.jar:1.36.0] at io.grpc.internal.DelayedClientCall$DelayedListener$3.run(DelayedClientCall.java :464) ~[grpc-core-1.36.0.jar:1.36.0] at io.grpc.internal.DelayedClientCall$DelayedListener.delayOrExecute(DelayedClientCall.java:428) ~[grpc-core-1.36.0.jar: 1.36.0] 在 ZF98ED07A4D5F50F7D E1410D905F1477FZ.grpc.internal.DelayedClientCall$DelayedListener.onClose(DelayedClientCall.java:461) ~[grpc-core-1.36.0.jar:1.36.0] at io.grpc.internal.ClientCallImpl.closeObserver(ClientCallImpl.java:553) ~[grpc-core-1.36.0.jar:1.36.0] at io.grpc.internal.ClientCallImpl.access$300(ClientCallImpl.java:68) ~[grpc-core-1.36.0.jar:1.36.0] at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInternal(ClientCallImpl.java:739) ~[grpc-core-1.36.0.jar:1.36.0] at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInContext(ClientCallImpl.java:718) ~[grpc E1410D905F1477FZ.grpc.internal.DelayedClientCall$DelayedListener.onClose(DelayedClientCall.java:461) ~[grpc-core-1.36.0.jar:1.36.0] at io.grpc.internal.ClientCallImpl.closeObserver(ClientCallImpl.java:553 ) ~[grpc-core-1.36.0.jar:1.36.0] at io.grpc.internal.ClientCallImpl.access$300(ClientCallImpl.java:68) ~[grpc-core-1.36.0.jar:1.36.0 ] at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInternal(ClientCallImpl.java:739) ~[grpc-core-1.36.0.jar:1.36.0] at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed .runInContext(ClientCallImpl.java:718) ~[grpc -core-1.36.0.jar:1.36.0] at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37) ~[grpc-core-1.36.0.jar:1.36.0] at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:123) ~[grpc-core-1.36.0.jar:1.36.0] at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130) ~[na:na] at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630) ~[na:na] at java.base/java.lang.Thread.run(Thread.java:832) ~[na:na] -core-1.36.0.jar:1.36.0] at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37) ~[grpc-core-1.36.0.jar:1.36.0] at io.grpc .internal.SerializingExecutor.run(SerializingExecutor.java:123) ~[grpc-core-1.36.0.jar:1.36.0] at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130) ~[na:na] at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630) ~[na:na] at java.base/java.lang.Thread.run(Thread. java:832) ~[na:na]

Is there something I am missing with bi-directional streaming with GRPC?使用 GRPC 进行双向流式传输有什么我缺少的吗?

I am trying to implement a bi-directional streaming service for all nodes in a cluster.我正在尝试为集群中的所有节点实现双向流服务。 Using this, these nodes are supposed to sync their states ie whenever any server would get any update using serveRequest request from any client, it would pass that information to other nodes in the cluster using streaming service syncState .使用这个,这些节点应该同步它们的状态,即每当任何服务器使用来自任何客户端的serveRequest请求获得任何更新时,它都会使用流服务syncState状态将该信息传递给集群中的其他节点。

For this, every node in the cluster has clients set up to connect to every other node.为此,集群中的每个节点都设置了客户端以连接到每个其他节点。 Clients initialization is one-time and a stream is set up (1 client has 1 stream per node) using which it is supposed to sync the latest state to other nodes.客户端初始化是一次性的,并且设置了 stream(1 个客户端每个节点有 1 个 stream),它应该使用它来将最新的 state 同步到其他节点。

Sample Proto样品原型

message MessageRequest {
  string policyId = 1;
  string txnId = 2;
  string clientId = 3;
}

message Acknowledgement {
  string serverId = 1;
  string txnId = 2;
}

service SyncState{
  rpc sync(stream MessageRequest) returns (stream Acknowledgement) {}
}

service ServeRequest{
  rpc newRequest(MessageRequest) returns (Acknowledgement) {}
}

SyncService同步服务

public class SyncStateService extends SyncStateServiceGrpc.SyncStateServiceImplBase {

    private static final Logger logger = LoggerFactory.getLogger(SyncStateService.class);
    private SyncManager manager;
    private Configuration config;

    public SyncStateService(SyncManager manager, Configuration config) {
        this.manager = manager;
        this.config = config;
    }

    @Override
    public StreamObserver<MessageRequest> sync(StreamObserver<Acknowledgement> responseObserver) {
        logger.info("Server received connection request");
        return new StreamObserver<MessageRequest>() {
            @Override
            public void onNext(MessageRequest request) {
                Acknowledgement ack = Acknowledgement.newBuilder().setTxnId(request.getTxnId()).setServerId(config.getClientId()).build();
                MessageRequest clone = MessageRequest.newBuilder().setClientId(config.getClientId()).setTxnId(request.getTxnId()).build();
                CompletableFuture.runAsync(() -> manager.sendMessage(clone));
                responseObserver.onNext(ack);
            }

            @Override
            public void onError(Throwable t) {
                logger.error("Error on server for client stream", t);
            }

            @Override
            public void onCompleted() {
                logger.info("client called on completed on stream, server closes response stream");
                responseObserver.onCompleted();
            }
        };
    }
}

Client Stream Manager客户 Stream 经理

public class SyncManager {
    private Map<String, SyncClient> client = new HashMap<>();
    private final Configuration  config;

    public SyncManager(Configuration  config) {
        this.config = config;
    }

    public void startStateSync(MessageRequest clone) {
        //This method is called whenever
        //ServeRequest APi is hit on any server
        config.getNodes().forEach(e->{
            SyncClient syncClient = client.get(e);
            if (syncClient== null){
                syncClient = new SyncClient(e);
            }
            MessageRequest gossipRequest = MessageRequest.newBuilder().setTxnId(clone.getTxnId())
                    .setPolicyId(clone.getPolicyId()).setClientId(config.getClientId()).build();
            syncClient.syncMessage(e, gossipRequest);
        });
    }

    public void sendMessage(MessageRequest clone) {
        // Server which has received state sync request
        //forwards the same info to other servers
        config.getNodes().forEach(e->{
            SyncClient syncClient = client.get(e);
            if (syncClient== null){
                syncClient = new SyncClient(e);
            }
            MessageRequest gossipRequest = MessageRequest.newBuilder().setTxnId(clone.getTxnId())
                    .setPolicyId(clone.getPolicyId()).setClientId(config.getClientId()).build();
            syncClient.syncMessage(e, gossipRequest);
        });
    }
}

Client:客户:

public class SyncClient {
    private static final Logger logger = LoggerFactory.getLogger(SyncClient.class);
    private final ManagedChannel channel;
    private final SyncStateServiceGrpc.SyncStateServiceStub stub;
    private final StreamObserver<MessageRequest> stream;

    public SyncClient(String node) {
        channel = ManagedChannelBuilder.forTarget(node)
                .usePlaintext()
                .keepAliveTime(new Long(2), TimeUnit.DAYS)
                .keepAliveTimeout(new Long(1), TimeUnit.DAYS)
                .keepAliveWithoutCalls(true)
                .build();
        stub = SyncStateServiceGrpc.newStub(channel);
        stream = getStreamObserver();
    }

    private StreamObserver<MessageRequest> getStreamObserver() {
        final StreamObserver<MessageRequest> stream;
        stream = stub.sync(new StreamObserver<>() {
            @Override
            public void onNext(Acknowledgement value) {
                String txnId = value.getTxnId();
                logger.info("Received message from server");
                String serverId = value.getServerId();

            }

            @Override
            public void onError(Throwable t) {
                logger.error("Error occurred", t);
            }

            @Override
            public void onCompleted() {
                logger.info("Completed");
            }
        });
        return stream;
    }
    
    public void syncMessage(String node, MessageRequest request) {
        logger.info("Sending message to:: {}", node);
        stream.onNext(request);
    }
}

Issues:问题:

  1. Whenever a client is setup, the server's sync method is never triggered(No logs on server, must be printed this Server received connection request )每当设置客户端时,从不触发服务器的同步方法(服务器上没有日志,必须打印此服务器收到的连接请求
  2. stream.onNext(request) on clients always throws error:客户端上的stream.onNext(request)总是抛出错误:

io.grpc.StatusRuntimeException: CANCELLED: io.grpc.Context was cancelled without error at io.grpc.Status.asRuntimeException(Status.java:535) ~[grpc-api-1.36.0.jar:1.36.0] at io.grpc.stub.ClientCalls$StreamObserverToCallListenerAdapter.onClose(ClientCalls.java:478) ~[grpc-stub-1.36.0.jar:1.36.0] at io.grpc.internal.DelayedClientCall$DelayedListener$3.run(DelayedClientCall.java:464) ~[grpc-core-1.36.0.jar:1.36.0] at io.grpc.internal.DelayedClientCall$DelayedListener.delayOrExecute(DelayedClientCall.java:428) ~[grpc-core-1.36.0.jar:1.36.0] at ZF98ED07A4D5F50F7D io.grpc.StatusRuntimeException: CANCELLED: io.grpc.Context was cancelled without error at io.grpc.Status.asRuntimeException(Status.java:535) ~[grpc-api-1.36.0.jar:1.36.0] at io .grpc.stub.ClientCalls$StreamObserverToCallListenerAdapter.onClose(ClientCalls.java:478) ~[grpc-stub-1.36.0.jar:1.36.0] at io.grpc.internal.DelayedClientCall$DelayedListener$3.run(DelayedClientCall.java :464) ~[grpc-core-1.36.0.jar:1.36.0] at io.grpc.internal.DelayedClientCall$DelayedListener.delayOrExecute(DelayedClientCall.java:428) ~[grpc-core-1.36.0.jar: 1.36.0] 在 ZF98ED07A4D5F50F7D E1410D905F1477FZ.grpc.internal.DelayedClientCall$DelayedListener.onClose(DelayedClientCall.java:461) ~[grpc-core-1.36.0.jar:1.36.0] at io.grpc.internal.ClientCallImpl.closeObserver(ClientCallImpl.java:553) ~[grpc-core-1.36.0.jar:1.36.0] at io.grpc.internal.ClientCallImpl.access$300(ClientCallImpl.java:68) ~[grpc-core-1.36.0.jar:1.36.0] at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInternal(ClientCallImpl.java:739) ~[grpc-core-1.36.0.jar:1.36.0] at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInContext(ClientCallImpl.java:718) ~[grpc E1410D905F1477FZ.grpc.internal.DelayedClientCall$DelayedListener.onClose(DelayedClientCall.java:461) ~[grpc-core-1.36.0.jar:1.36.0] at io.grpc.internal.ClientCallImpl.closeObserver(ClientCallImpl.java:553 ) ~[grpc-core-1.36.0.jar:1.36.0] at io.grpc.internal.ClientCallImpl.access$300(ClientCallImpl.java:68) ~[grpc-core-1.36.0.jar:1.36.0 ] at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInternal(ClientCallImpl.java:739) ~[grpc-core-1.36.0.jar:1.36.0] at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed .runInContext(ClientCallImpl.java:718) ~[grpc -core-1.36.0.jar:1.36.0] at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37) ~[grpc-core-1.36.0.jar:1.36.0] at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:123) ~[grpc-core-1.36.0.jar:1.36.0] at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130) ~[na:na] at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630) ~[na:na] at java.base/java.lang.Thread.run(Thread.java:832) ~[na:na] -core-1.36.0.jar:1.36.0] at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37) ~[grpc-core-1.36.0.jar:1.36.0] at io.grpc .internal.SerializingExecutor.run(SerializingExecutor.java:123) ~[grpc-core-1.36.0.jar:1.36.0] at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130) ~[na:na] at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630) ~[na:na] at java.base/java.lang.Thread.run(Thread. java:832) ~[na:na]

Is there something I am missing with bi-directional streaming with GRPC?使用 GRPC 进行双向流式传输有什么我缺少的吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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