当前位置: 首页 > 知识库问答 >
问题:

gRPC下游的优雅停机

端木宏才
2023-03-14
syntax = "proto3";

package pb;

message SimpleRequest {
    int64 number = 1;
}

message SimpleResponse {
    int64 doubled = 1;
}

// All the calls in this serivce preform the action of doubling a number.
// The streams will continuously send the next double, eg. 1, 2, 4, 8, 16.
service Test {
    // This RPC streams from the server only.
    rpc Downstream(SimpleRequest) returns (stream SimpleResponse);
}

我能够成功地打开一个流,并不断地从服务器获得下一个翻倍的数字。

我的go运行代码如下所示:

ctxDownstream, cancel := context.WithCancel(ctx)
downstream, err := testClient.Downstream(ctxDownstream, &pb.SimpleRequest{Number: 1})
for {
    responseDownstream, err := downstream.Recv()
    if err != io.EOF {
        println(fmt.Sprintf("downstream response: %d, error: %v", responseDownstream.Doubled, err))

        if responseDownstream.Doubled >= 32 {
            break
        }
    }
}
cancel() // !!This is not a graceful shutdown
println(fmt.Sprintf("%v", downstream.Trailer()))

我遇到的问题是使用上下文取消意味着我的downstream.trailer()响应为空。是否有一种方法可以从客户端优雅地关闭此连接并接收downstream.trailer()。

func (b *binding) Downstream(req *pb.SimpleRequest, stream pb.Test_DownstreamServer) error {
    request := req

    r := make(chan *pb.SimpleResponse)
    e := make(chan error)
    ticker := time.NewTicker(200 * time.Millisecond)
    defer func() { ticker.Stop(); close(r); close(e) }()

    go func() {
        defer func() { recover() }()
        for {
            select {
            case <-ticker.C:
                response, err := b.Endpoint(stream.Context(), request)
                if err != nil {
                    e <- err
                }
                r <- response
            }
        }
    }()

    for {
        select {
        case err := <-e:
            return err
        case response := <-r:
            if err := stream.Send(response); err != nil {
                return err
            }
            request.Number = response.Doubled
        case <-stream.Context().Done():
            return nil
        }
    }
}

您仍然需要用一些信息填充预告片。我使用grpc.StreamServerInterceptor来完成这项工作。

共有1个答案

孔和风
2023-03-14

根据grpc go文档

Trailer从服务器返回Trailer元数据(如果有的话)。只有在Stream.CloseAndRecv返回或Stream.Recv返回非零错误(包括IO.EOF)之后才可以调用它。

因此,如果您想在客户机中阅读预告片,请尝试如下所示

ctxDownstream, cancel := context.WithCancel(ctx)
defer cancel()
for {
  ...
  // on error or EOF
  break;
}
println(fmt.Sprintf("%v", downstream.Trailer()))
 类似资料:
  • Dubbo 是通过 JDK 的 ShutdownHook 来完成优雅停机的,所以如果用户使用 kill -9 PID 等强制关闭指令,是不会执行优雅停机的,只有通过 kill PID 时,才会执行。 原理 服务提供方 停止时,先标记为不接收新请求,新请求过来时直接报错,让客户端重试其它机器。 然后,检测线程池中的线程是否正在运行,如果有,等待所有线程执行完成,除非超时,则强制关闭。 服务消费方 停

  • 本文向大家介绍Dubbo如何优雅停机?相关面试题,主要包含被问及Dubbo如何优雅停机?时的应答技巧和注意事项,需要的朋友参考一下 Dubbo 是通过 JDK 的 ShutdownHook 来完成优雅停机的,所以如果使用 kill -9 PID 等强制关闭指令,是不会执行优雅停机的,只有通过 kill PID 时,才会执行。  

  • 不论是什么类型的应用,都会希望在服务停止前能够收到停止通知,有一定的时间做退出前的释放资源、关闭连接、不再接收外部请求等工作。我们对所有应用的优雅停止配置提供了一个全面指导,也提供了每种类型服务,从开发到部署到应用引擎v2的测试优雅停止功能的完整流程。 容器优雅停止最简单办法 当退出容器前,会将容器从服务提供列表中移除,使得外部请求不再打在其上,同时执行退出前可执行Hook。 在这里,我们设置在停

  • 问题内容: 如何在Linux和Windows中正常停止Java进程? 什么时候被调用,什么时候不被调用? 终结器又如何呢? 我可以从外壳向Java进程发送某种信号吗? 我正在寻找最好的便携式解决方案。 问题答案: 在所有未强制终止VM的情况下,都会执行关机挂钩。因此,如果要发出“标准” kill(通过kill命令),则它们将执行。同样,它们将在调用后执行。 但是强行杀死(或),然后它们将不会执行。

  • 问题内容: 我写了一个线程,它花费太多时间执行,而且似乎还没有完全完成。我想优雅地停止线程。有什么帮助吗? 问题答案: 做到这一点的好方法是让一个线程保护一个Thread的变量,并在你要停止它的时候将其设置为外部变量,例如: `class MyThread extends Thread { volatile boolean finished = false; public void stopMe(

  • 本文向大家介绍详解Springboot 优雅停止服务的几种方法,包括了详解Springboot 优雅停止服务的几种方法的使用技巧和注意事项,需要的朋友参考一下 在使用Springboot的时候,都要涉及到服务的停止和启动,当我们停止服务的时候,很多时候大家都是kill -9 直接把程序进程杀掉,这样程序不会执行优雅的关闭。而且一些没有执行完的程序就会直接退出。 我们很多时候都需要安全的将服务停止,