0

Python gRPC message does not serialize first field. I updated protos and cleaned everything many times but it is not fixed. You can see logs, settings_dict has stop field but after passing these fields to AgentSetting it is not seen in logs and server side. Also I tried to pass stop field manually but it is not seen as well. Annoying thing is that gRPC does not throw any exception it is accepting stop field but it is not sending to server also it is not seen in AgentSetting while printing but stop field is reachable like agent_setting.stop.

This is my proto file:

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) {};
}

This is my code snippet:

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")

Logs:

|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"
madogan
  • 605
  • 7
  • 11

1 Answers1

0

In proto3, an unset value and a default value are considered equivalent.

So stop: false is considered equivalent to omitting stop entirely.

See 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.

Note that this is different from proto2.

Dietrich Epp
  • 205,541
  • 37
  • 345
  • 415