Nameko - invoking RPC method from another service

2.1k views Asked by At

I am trying to understand how nameko works for basic RPC. I am looking to define microservices in separate files and being able to run them from command shell. With this structure service2 is not being able to invoke service1's RPC method. What is missing to get this working?

I have the following file structure:

-rwxrwxr-x 1 user user 240 Dec 15 01:49 nameko.sh*
-rw-rw-r-- 1 user user 251 Dec 15 01:46 service1.py
-rw-rw-r-- 1 user user 305 Dec 15 01:47 service2.py

Content of files are:

$ cat nameko.sh
#!/bin/bash
/usr/local/bin/nameko run service1:Microservice1 &
nameko_id=$!
echo 'Microservice 1 PID: ' $nameko_id
/usr/local/bin/nameko run service2:Microservice2 &
nameko_id=$!
echo 'Microservice 2 PID: ' $nameko_id
wait 2> /dev/null


$ cat service1.py
# -*- coding: utf-8 -*-
from nameko.rpc import rpc, RpcProxy
class Microservice1(object):
    name = "microservice1"
    @rpc
    def hello(self):
        print 'Microservice1 hello method invoked'
        return True

$ cat service2.py
# -*- coding: utf-8 -*-
from nameko.rpc import rpc, RpcProxy
class Microservice2(object):
    name = "microservice2"
    microservice1 = RpcProxy('microservice1')
    microservice1.hello()
    @rpc
    def hello(self):
        print 'Microservice2 hello method invoked'
        return True

And I am not being able to understand how to invoke hello method in Microservice 1 from Microservice 2:

$ ./nameko.sh
Microservice 1 PID:  14782
Microservice 2 PID:  14783
Traceback (most recent call last):
  File "/usr/local/bin/nameko", line 11, in <module>
    sys.exit(main())
  File "/usr/local/lib/python2.7/dist-packages/nameko/cli/main.py", line 66, in main
    args.main(args)
  File "/usr/local/lib/python2.7/dist-packages/nameko/cli/commands.py", line 85, in main
starting services: microservice1
    main(args)
  File "/usr/local/lib/python2.7/dist-packages/nameko/cli/run.py", line 179, in main
    import_service(path)
  File "/usr/local/lib/python2.7/dist-packages/nameko/cli/run.py", line 46, in import_service
    __import__(module_name)
  File "./service2.py", line 5, in <module>
    class Microservice2(object):
  File "./service2.py", line 11, in Microservice2
    microservice1.hello()
AttributeError: 'RpcProxy' object has no attribute 'hello'
Connected to amqp://guest:**@127.0.0.1:5672//

But invoking nameko shell and running rpc method from microservice1 works:

Broker: pyamqp://guest:guest@localhost
>>> n.rpc.microservice1.hello()
True

Added information

Following Matt's answer I have edited service2.py as follows:

# -*- coding: utf-8 -*-
from nameko.rpc import rpc, RpcProxy
class Microservice2(object):
    name = "microservice2"

    @rpc
    def toctoc(self):
        print 'Microservice2 called hello method from Microservice1'
        m1 = RpcProxy('microservice1')
        m1.hello()
        return True

Now both services run, But still does not work, when I run a namejo shell and invoke toctoc method from Microservice2:

$ nameko shell
Nameko Python 2.7.12 (default, Nov 19 2016, 06:48:10)
[GCC 5.4.0 20160609] shell on linux2
Broker: pyamqp://guest:guest@localhost
>>> n.rpc.microservice2.toctoc()
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/usr/local/lib/python2.7/dist-packages/nameko/rpc.py", line 374, in 
__call__
    return reply.result()
  File "/usr/local/lib/python2.7/dist-packages/nameko/rpc.py", line 332, in 
result
    raise deserialize(error)
RemoteError: AttributeError 'RpcProxy' object has no attribute 'hello'
>>>

Last working code

With the help provided in the answers, a working version of this would be (in case it clarifies/helps others):

$ cat nameko.sh
#!/bin/bash
/usr/local/bin/nameko run service1:Microservice1 &
nameko_id=$!
echo 'Microservice 1 PID: ' $nameko_id
/usr/local/bin/nameko run service2:Microservice2 &
nameko_id=$!
echo 'Microservice 2 PID: ' $nameko_id
wait 2> /dev/null


$ cat service1.py
# -*- coding: utf-8 -*-
from nameko.rpc import rpc, RpcProxy
class Microservice1(object):
    name = "microservice1"
    @rpc
    def hello(self):
        print 'Microservice1 hello method invoked'
        return True

$ cat service2.py
# -*- coding: utf-8 -*-
from nameko.rpc import rpc, RpcProxy
class Microservice2(object):
    name = "microservice2"
    microservice1 = RpcProxy('microservice1')
    @rpc
    def remote_hello(self):
        print 'Microservice2 invokes hello method from Microservice1'
        self.microservice1.hello()
        return True
2

There are 2 answers

0
second On BEST ANSWER

there's an example of service-to-service rpc in the docs

class ServiceX:
    name = "service_x"

    # this _declares_ the dependency (and triggers nameko to set things up)
    y = RpcProxy("service_y")


    # note that the proxy isn't usable until a service worker is
    # running, i.e. until you're inside an executing method
    # y.foo() <- this doesn't work. 

    @rpc
    def remote_method(self, value):
        res = u"{}-x".format(value)

        # this _invokes_ the dependency
        return self.y.append_identifier(res)
2
Matt On

The problem is that service2.py isn't valid. You can't invoke the RPC proxy outside of a service method.

If you want to call a running service from an external script, use the standalone proxy.