目 录CONTENT

文章目录
Go

GRPC 中 context的应用!

Hello!你好!我是村望~!
2023-05-24 / 0 评论 / 0 点赞 / 204 阅读 / 765 字
温馨提示:
我不想探寻任何东西的意义,我只享受当下思考的快乐~

GRPC 中 context的应用!

求取消和超时控制

  • context.WithTimeout

gRPC上下文包含一个取消通知,当客户端取消请求或者请求超时时,可以通过上下文来通知服务器端停止处理该请求。

syntax = "proto3";
option go_package = "./demo"; // go_package 指定了编译后生成文件的路径,也对应了生成后的包名!

service DemoService {
  rpc ProcessRequest(RequestMessage) returns (ResponseMessage);
}

message RequestMessage {
  string data = 1;
}

message ResponseMessage {
  string result = 1;
}

实现写服务端 ProcessRequest服务方法(客户端传递过来的是一个context.WithTimeoutcontext,在指定时间会调用Done)

func (d DemoService) ProcessRequest(ctx context.Context, req *demo.RequestMessage) (*demo.ResponseMessage, error) {
	time.Sleep(3 * time.Second) // 模拟服务端处理业务3s
	select {
	case <-ctx.Done():
		// 请求已取消或超时
		fmt.Println("超时了!")
		return nil, ctx.Err()
	default:
		// 处理请求
		result := "Processed: " + req.GetData()
		return &demo.ResponseMessage{Result: result}, nil
	}
}

上面的代码我们使用 Sleep 模拟了业务的处理时间!如果超过了客户端context指定的超时时间,就会返回超时的错误!

客户端代码实现

func main() {
	conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure())
	if err != nil {
		log.Fatalf("Failed to connect: %v", err)
	}
	defer conn.Close()

	client := demo.NewDemoServiceClient(conn)

	// 客户端2s后就会执行cancel!
	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
	defer cancel()
	req := &demo.RequestMessage{
		Data: "Hello, gRPC!",
	}

	res, err := client.ProcessRequest(ctx, req)
	if err != nil {
		log.Fatalf("Request error: %v", err)
	}

	log.Printf("Response: %s", res.GetResult())
}

上面的客户端代码!就是在调用服务端方法的时候,传入了一个2s 超时的 TimeoutContext,上面服务端的业务逻辑处理了三秒,那么此时!服务端就会收到从context.done 然后返回err给客户端!!

传递元数据 METADAT

传递元数据:上下文可以用于传递请求相关的元数据,比如身份验证凭据、请求标识符等。服务器端可以通过上下文来访问这些元数据并根据需要进行处理。

GRPC客户端发送metadata

  • metadata.Pairs("key", "val") 创建 Meta data
  • 这里使用 metadata.NewOutgoingContext 创建一个 context!传入我们的Meta data
md := metadata.Pairs("token", "1111") // metadata.Pairs 设置元数据信息!
ctxMD := metadata.NewOutgoingContext(context.Background(), md)
client := demo.NewDemoServiceClient(conn)
// 客户端2s后就会执行cancel!
ctx, cancel := context.WithTimeout(ctxMD, 2*time.Second)
defer conn.Close()
defer cancel()
req := &demo.RequestMessage{
	Data: "Hello, gRPC!",
}
res, err := client.ProcessRequest(ctx, req)
if err != nil {
	log.Fatalf("Request error: %v", err)
}

服务端通过 metadata.FromIncomingContext(ctx) 接受 ,从 context 获取 Metadata

// UnaryInterceptor 实现拦截器接口的方法
func (i *interceptor) UnaryInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
	// 在请求到达处理程序之前执行的代码
	log.Println("Before handling request")
	if outgoingContext, b := metadata.FromIncomingContext(ctx); b {
		fmt.Println(outgoingContext.Get("token"))
	} else {
		fmt.Println("no metadata token!")
	}
	// 调用实际的处理程序
	resp, err = handler(ctx, req)

	// 在处理程序完成后执行的代码
	log.Println("After handling request")
	return resp, err
}

image-20230524120408007

0

评论区