2

I'm experiencing a strange behaviour while trying to serialize some data to send as argument to a remote procedure using Nameko and rabbitmq to a microservice:

A semplification of the problem structured into 3 files under a dir named project:

serializer.py, the custom json encoding/decoding objects

from enum import Enum
import json
from project.service import CustomEnum

class CustomEncoder(json.JSONEncoder):
    def default(self, o):
        if isinstance(o, CustomEnum):
            #  return {'__enum__': str(o)}
            return {'__enum__': o.name}
        return {'__{}__'.format(o.__class__.__name__): o.__dict__}

class CustomDecoder(json.JSONDecoder):
    def __init__(self, *args, **kwargs):
        json.JSONDecoder.__init__(self, 
                                  object_hook=self.object_hook, 
                                  *args, **kwargs)

    def object_hook(self, o):
        if '__enum__' in o:
            return CustomEnum[o['__enum__']]
            # name, member = o['__enum__'].split('.')
            # return getattr(ENUMS[name], member)
        return o

service.py, the basic microservice

from enum import Enum
from nameko.rpc import rpc
import json

from project.serializer import CustomDecoder


class CustomEnum(Enum):
    A = 0
    B = 1

class Service(object):
    name = "service"

    @rpc
    def get_enum(self, enum_type):
        enum_type = json.loads(enum_type, cls=CustomDecoder)
        if enum_type == CustomEnum.A:
            return "A"
        elif enum_type == CustomEnum.B:
            return "B"
        return "NO ENUM"

Nameko shell to try out, after starting a rabbitMQ docker instance and nameko run of the service by following these steps:

  • $ docker run -d --hostname rabbit --name my-rabbit -p 15672:15672 -p 5672:5672 rabbitmq:3-management
  • $ nameko run project.service --broker amqp://guest:guest@localhost
  • $ nameko shell --broker amqp://guest:guest@localhost

Here the shell output after testing it:

In [1]: import json
In [2]: from project.serializer import CustomEncoder
In [3]: from project.service import CustomEncoder
In [4]: serialized = json.dumps(CustomEnum.A, cls=CustomEncoder)
In [5]: n.rpc.service.get_enum(serialized)
NO ENUM

It seems that after being deserialized on the remote procedure type(enum_type) == type(CustomEnum) gives False, while trying it out in the nameko shell it perfectly serialized and deserialize the enum subclass type. Could it have something to do with the serialization of already serialized data by nameko itself? I know I should register the custom serializer to the kombu.serialization.register but I'm stuck to this and I'd like to know why this happen.

CodeP
  • 274
  • 2
  • 7
  • Please fix your code in `CustomEncoder.default` -- the `elif` is wrong (`SyntaxError`). – Ethan Furman Jul 05 '17 at 15:07
  • You're right sorry, copy/pasted from a hacky semplification. Fixed it, thank you. – CodeP Jul 05 '17 at 15:23
  • i can't reproduce this: `n.rpc.service.get_enum(serialized) Out[9]: 'A'` – second Jul 05 '17 at 19:58
  • Ok, It seems that there was something about my dev environment, rewriting code and moving `Enum` classes in a separate module solved the issue. Thank you. – CodeP Jul 07 '17 at 06:44
  • You have a circular import in your simplified example, but having fixed that I can't reproduce either. Your `enum_type` argument is actually a string, and Nameko will encode it and send it as JSON over the wire. You can verify this by inspecting the message and its headers in RabbitMQ. I see `content_encoding: utf-8`, `content_type: application/json`, `payload: {"args": ["{\"__enum__\": \"A\"}"], "kwargs": {}}` – Matt Jul 07 '17 at 09:13

0 Answers0