gRPC 对冲请求取消流程

本文详细解析了gRPC客户端和服务端在接收到流取消请求后的处理流程。客户端在接收到对冲请求的一个完成时,会取消其他请求,并发送RST_STREAM。服务端在接收到RST_STREAM后,会取消相应的流并关闭监听器。整个过程涉及到上下文的取消、任务的调度和网络通信的细节,确保了请求的正确管理和资源的有效释放。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

当客户端接收到对冲请求集合中的一个完成时,会取消其他的请求,被取消的请求最终会提交一个 CancelClientStreamCommand,发送一个 RST_STEAM 请求;当服务端接受到这个流后,如果监听器还没有关闭,会执行取消上下文的操作,最终将这个请求取消

客户端

当客户端成功接收到响应会,会在 io.grpc.internal.RetriableStream.Sublistener#close 中将成功的流进行提交

  • io.grpc.internal.RetriableStream#commit$CommitTask#run

在提交时,会通过提交 CommitTask 将其他的流取消

class CommitTask implements Runnable {
   
    @Override
    public void run() {
   
        // 遍历保存的枯竭的流,如果不是最后提交的流,则都取消
        for (Substream substream : savedDrainedSubstreams) {
   
            if (substream != winningSubstream) {
   
                substream.stream.cancel(CANCELLED_BECAUSE_COMMITTED);
            }
        }
        // 如果有重试中的,则取消
        if (retryFuture != null) {
   
            retryFuture.cancel(false);
        }
        // 如果有对冲中的,则取消
        if (hedgingFuture != null) {
   
            hedgingFuture.cancel(false);
        }

        // 将当前流从未提交的流中移除
        postCommit();
    }
}
  • io.grpc.internal.AbstractClientStream#cancel

使用指定的原因取消流

public final void cancel(Status reason) {
   
    Preconditions.checkArgument(!reason.isOk(), "Should not cancel with OK status");
    cancelled = true;
    abstractClientStreamSink().cancel(reason);
}
  • io.grpc.netty.shaded.io.grpc.netty.NettyClientStream.Sink#cancel

提交取消流的指令

public void cancel(Status status) {
   
    PerfMark.startTask("NettyClientStream$Sink.cancel");

    try {
   
        NettyClientStream.this.writeQueue.enqueue(new CancelClientStreamCommand(NettyClientStream.this.transportState(), status), true);
    } finally {
   
        PerfMark.stopTask("NettyClientStream$Sink.cancel");
    }

}
  • io.grpc.netty.shaded.io.grpc.netty.NettyClientHandler#write

在执行写入消息时,写入取消指令

public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
   
    if (msg instanceof CreateStreamCommand) {
   
        this.createStream((CreateStreamCommand)msg, promise);
    } else if (msg instanceof SendGrpcFrameCommand) {
   
        this.sendGrpcFrame(ctx, (SendGrpcFrameCommand)msg, promise);
    } else if (msg instanceof CancelClientStreamCommand) {
   
在前端使用GRPCgRPC,高性能、开源的RPC框架)时,通常需要对基本的请求方法进行封装,以便于在各种场景下调用服务。以下是创建通用请求方法的一般步骤: 1. 引入依赖:首先安装gRPC客户端库,例如在TypeScript项目中,可能会引入`@grpc/grpc-js`或`@grpc/web`(针对Web环境)。 2. 定义Service:在前端定义一个代表后端服务的JavaScript接口(常称为.proto文件),描述你要调用的服务方法和消息结构。 3. 创建Client:创建一个gRPC客户端实例,传入后端服务器地址和服务名。 4. 编写封装方法:创建一个函数,接收必要的参数(通常是请求体和回调函数),然后使用`client.methodName()`调用对应的GRPC方法。这个函数可以处理错误处理、序列化/反序列化数据以及发起网络请求。 ```typescript import * as grpc from '@grpc/grpc-js'; // 假设有个名为UserService的Service const userServiceProto = ...; // 应从.proto文件加载 async function call GRPCAPI(methodName: string, request: any, callback: (response: any) => void): Promise<void> { const client = new UserService(yourGrpcEndpoint, grpc.credentials.createInsecure()); try { const response = await client[methodName](request); callback(response); } catch (error) { console.error('Error while calling gRPC API:', error); callback(null); // 或者按需处理错误 } } ``` 5. 使用封装后的函数:现在可以在前端应用中多次调用`callGRPCAPI`,只需要提供对应的服务方法名称、请求对象和处理响应的回调。 ```typescript callGRPCAPI('getUser', { userId: '123' }, (response) => { if (response) { // 处理返回的用户信息 } else { // 处理错误 } }); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值