Moleculer: Actions in services with ProtoBuf and NATS cannot return 0 and false.

Created on 4 Apr 2019  路  12Comments  路  Source: moleculerjs/moleculer

Prerequisites

Please answer the following questions for yourself before submitting an issue.

  • [x] I am running the latest version
  • [x] I checked the documentation and found no answer
  • [x] I checked to make sure that this issue has not already been filed
  • [x] I'm reporting the issue to the correct repository

Expected Behavior

Be able to receive 0 and false as a result of some action in a service using NATS and Protobuf.

Current Behavior

0 and false are received as undefined.

Failure Information

Protobuf serialize or deserialize the message incorrectly and turns 0 and false results into undefined

Steps to Reproduce

  1. step 1
  2. step 2
  3. you get it...

Reproduce code snippet

const broker = new ServiceBroker({
    transporter: "NATS",
    serializer: 'ProtoBuf'
});

broker.createService({
    name: "greeter",
   version: 1,
    actions: {
        willReturnFalse() {
            return false;
        },

        willReturnZero() {
            return 0;
        }
});

describe("Test 'greeter' service", () => {

    const broker = new ServiceBroker({ transporter: 'nats://localhost:4222', serializer: 'ProtoBuf' });

    beforeAll(async () => {
        await broker.start();
        await broker.waitForServices([{ name: 'greeter', version: 1 }]);
    });

    afterAll(() => broker.stop());

    describe("Test 'greeter.willReturnFalse' action", () => {
        it("should return false", () => {
            expect(broker.call("v1.greeter.willReturnFalse")).resolves.toBe(false);
        });
    });


    describe("Test 'greeter.willReturnFalse' action", () => {
        it("should return 0", () => {
            expect(broker.call("v1.greeter.willReturnZero")).resolves.toBe(0);
        });
    });
});

// both tests will fail receiving undefined


EXAMPLE READY TO RUN:

https://github.com/alvarocantador/moleculer-zero-and-false-bug

Context

Please provide any relevant information about your setup. This is important in case the issue is not reproducible except for under certain conditions.

  • Moleculer version: 0.13.8
  • NodeJS version: 10.15.3
  • Operating System: MacOS

Failure Logs


High Need reproduce Bug

Most helpful comment

I've fixed it.

All 12 comments

@AndreMaz could you help with it?

@hoanganh25991 Could you check once?

Hi @alvarocantador ,
I've tested ProtoBuf on NATS, the serializer work as expected
image

In my test, I only use moleculer-cli to init minimal project template.
I guess your API service make change on value.

Example ready to run:
https://github.com/hoanganh25991/protobuf-serialize-false-zero

@icebob @hoanganh25991 In your case, the greeter is a local service and its work as expected. Try to run dev in a shell and call it in another repl, you will see undefined.

I have the bug example here: https://github.com/alvarocantador/moleculer-zero-and-false-bug

In this case I am using the moleculer-runner inside of a docker image, and via NATS in another broker, I am trying to call the willReturnFalse and willReturnZero actions.

Only in the npm run dev shell:
image

Now with an REPL:
image

  • WITH A RUNNER

Hi @alvarocantador ,

By default, broker config "prefer local", which lead to call without send through NATS.
I see your issue when add another repl.

I digging in transporter & serializer code to figure out.

Protobuf serialize flow:

  • Convert data to string
  • Build up buffer from that string
  • Encode with proto/packets.proto.js before send out

I think the if check falsy value on obj.data in serializer/base.js cause the problem:

  • JSON.stringify never hit
  • cause Buffer.from never hit
  • cause deserialize return undefined

As what I test, remove the falsy check, response return false, 0 as expected

https://github.com/moleculerjs/moleculer/blob/master/src/serializers/base.js#L98

image

Protobuf Serializer

https://github.com/moleculerjs/moleculer/blob/master/src/serializers/protobuf.js

Serialize

base.js > serializeCustomFields
Falsy value not converted to string

case P.PACKET_RESPONSE: {
  obj.meta = JSON.stringify(obj.meta);
  if (obj.data) {
    if (!obj.stream) {
      obj.data = JSON.stringify(obj.data);
    }
  }
}

protobuf.js > serializeCustomFields
Buffer not built up

case P.PACKET_RESPONSE: {
  if (obj.data && !obj.stream)
    obj.data = Buffer.from(obj.data);
  break;
}

Deserialize

protobuf.js > deserializeCustomFields
No data key on obj, return undefined

case P.PACKET_RESPONSE: {
  if (obj.data && !obj.stream) {
    if (obj.data.length)
      obj.data = obj.data.toString("utf8");
    else 
      obj.data = undefined; 
  }
  break;
}

@hoanganh25991 good catch. Thank you, I'm fixing.

I've fixed. @hoanganh25991 @alvarocantador could you check it to install master with npm i moleculerjs/moleculer?

Hi @icebob ,

I've tested your fix in "moleculerjs/moleculer" package, now Protobuf serialize correctly on false, 0 case. However, it return as "undefined" on null case.

protobuf-serialize-false-zero-2019-04-07 14-32-45

As my test above, on "greeter.willReturnNull", Protobuf deserialize as "undefined".

Test example ready to run:
https://github.com/hoanganh25991/protobuf-serialize-false-zero

Thanks. I'm checking...

I've fixed it.

Was this page helpful?
0 / 5 - 0 ratings