为什么 gRPC Python 看不到第一个字段?

Why gRPC Python does not see first field?

Python gRPC 消息不序列化第一个字段。我多次更新原型并清理所有内容,但未修复。您可以看到日志,settings_dictstop 字段,但在将这些字段传递给 AgentSetting 后,在日志和服务器端看不到。我也尝试手动传递 stop 字段,但也没有看到。烦人的是,gRPC 不会抛出任何异常,它正在接受 stop 字段,但它不会发送到服务器,它在打印时也不会在 AgentSetting 中看到,但是 stop 字段可以像 agent_setting.stop.

这是我的原型文件:

syntax = 'proto3';

import "base.proto";

message ConnectionCheckRequest {
  string host_name = 1;
}

message RecordChunkRequest {
  string host_name = 1;
  string name = 2;
  bytes chunk = 3;
  uint32 chunk_index = 4;
  uint32 chunk_number = 5;
}

message AgentSetting {
    bool stop = 1;

    bool connection = 2;
    bool registered = 3;

    string image_mode = 4;

    uint32 sending_fail_limit = 5;
    uint64 limit_of_old_records = 6;

    string offline_records_exceed_policy = 7;
}

message AgentSettingRequest {
    AgentSetting agent_setting = 1;
    string host_name = 2;
}

message AgentSettingResponse {
    AgentSetting agent_setting = 1;
}

message AgentRegistryRequest {
    AgentSetting agent_setting = 1;
    string host_name = 2;
}

service Chief {
  rpc agent_update_setting(AgentSettingRequest) returns (AgentSettingResponse) {};
  rpc agent_registry(AgentRegistryRequest) returns (Response) {};
  rpc send (stream RecordChunkRequest) returns (Response) {};
  rpc connection_check (ConnectionCheckRequest) returns (Response) {};
}

这是我的代码片段:

def register():
    try:
        with insecure_channel(settings.server_address) as channel:
            setting_dict = settings.dict()

            logger.info(f'\nSetting Dict: {setting_dict}')

            agent_setting = AgentSetting(**setting_dict)

            logger.info(f'\nAgent Setting Instance: \n{agent_setting}')

            response = ChiefStub(channel).agent_registry(
                AgentRegistryRequest(
                    agent_setting=agent_setting,
                    host_name=settings.host_name
                )
            )
            return response
    except Exception as e:
        logger.exception(f'Register Error: {str(e)}')
        return Response(success=False, message="failure")

日志:

|2020-05-05T18:33:56.931140+0300| |5480| |INFO| |reqs:register:28| 
Setting Dict: {'stop': False, 'connection': True, 'registered': False, 'image_mode': 'RGB', 'sending_fail_limit': 3, 'limit_of_old_records': 5368709120, 'offline_records_exceed_policy': 'OVERWRITE'}
|2020-05-05T18:33:56.932137+0300| |5480| |INFO| |reqs:register:32| 
Agent Setting Instance: 
connection: true
image_mode: "RGB"
sending_fail_limit: 3
limit_of_old_records: 5368709120
offline_records_exceed_policy: "OVERWRITE"

在 proto3 中,未设置的值和默认值被认为是等价的。

所以 stop: false 被认为等同于完全省略 stop

Language Guide (proto3)

Note that for scalar message fields, once a message is parsed there's no way of telling whether a field was explicitly set to the default value (for example whether a boolean was set to false) or just not set at all: you should bear this in mind when defining your message types. For example, don't have a boolean that switches on some behaviour when set to false if you don't want that behaviour to also happen by default. Also note that if a scalar message field is set to its default, the value will not be serialized on the wire.

请注意,这与 proto2 不同。