go实现Grpc 传输泛类型的消息体

背景

最近在做的项目准备通过grpc进行通信,server端返回的数据类型是不固定的(通过go语言访问redis 中执行redis命令返回的数据类型是interface{}),所以我的诉求是client层可以通过grpc接收到这种泛类型。

不将解析结果集的逻辑放在server层主要是考虑了两个方面

  1. 执行redis命令返回的数据类型包括多种,其中包括嵌套数组,相应的protoc文件中消息结构体定义会变得比较复杂
  2. server层作为agent,如果将过多的逻辑放到这一层,后期的迭代更新成本会较大

有两种解决思路

备注:方法1在我这个场景下行不通,但是也记录以下大概的实践方法

1. 使用proto3的Any定义泛类型

protocol文件中通过Any定义泛类型字段

import "google/protobuf/any.proto";

message AgentExecRedisRes{
   
    google.protobuf.Any AgentLocalExecRedisCmdRes = 1;

server 端处理客户端rpc请求的伪代码

  • Any字段需要通过MarshalAny(m proto.Message) (anypb.Any, error)方法转换为anypb.Any类型,然后grpc将其传给client端,client端再通过ptypes.UnmarshalAny(any *anypb.Any, m proto.Message) 转换成protoc3支持的类型
  • server端转成*anypb.Any的条件是你传入的类型必须要是protoc3支持的数据类型,所以又到了绕不开的这一个问题了:需要在server层完成数据解析
any "github.com/golang/protobuf/ptypes/any"

// 单次rpc交互函数,用于agent-server单次交互,同步交互
func (server *ProxyAgentServer) ReceiveSyncTaskMsgFromServer(ctx context.Context,
	taskMsg *agentpb.ManagerTaskMsg) (*agentpb.ManagerTaskRespons, error) {
   
	var err error
	var reply interface{
   }
	// 构造rpc返回消息
	responsMsg := &agentpb.ManagerTaskRespons{
   
		Timestamp: time.Now().UnixNano(),
		TaskId:    taskMsg.TaskId,
		TaskType:  taskMsg.GetTaskType(),
		ErrorCode: 0,
		ErrorMsg:  "",
	}

	switch taskMsg.GetTaskType() {
   
	case agentpb.TaskType_REDIS_CMD_EXEC:
		reply, err = worker.RedisCmdExec(taskMsg.GetTaskExecRedis().GetServerType(),
			taskMsg.GetTaskExecRedis().GetPort(), taskMsg.GetTaskExecRedis().GetRedisCmd())
		if err != nil {
   
			common.Log.Warn("Failed to execute redis cmd task taskid=[%v] reason=[%v]",
				taskMsg.GetTaskId(), err)
		} else {
   
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值