Proper serviceRunner usage

Hi Guys!

I’m trying to figure out how to use the serviceRunner and I have a lot of questions. More than answers.

my first example code app.py:

import eventlet
from nameko.rpc import rpc
from nameko.runners import ServiceRunner


eventlet.monkey_patch()

class ServiceA
    name = "service_a"
    @rpc
    def x(self):
        return "A"


class ServiceB
    name = "service_b"
    @rpc
    def x(self):
        return "B"

runner = ServiceRunner(config={"AMQP_URI":"pyamqp://quest:quest@192.168.1.42"})
runner.add_service(ServiceA)
runner.add_service(ServiceB)

runner.start()

Im trying start service with nameko run --config test.yaml app and got 4 connections from app.py

Connected to amqp://quest:**@192.168.1.42:5672//
Connected to amqp://quest:**@192.168.1.42:5672//
starting services: service_a, service_B
Connected to amqp://quest:**@192.168.1.42:5672//
Connected to amqp://quest:**@192.168.1.42:5672//

Ok, lets try reformat code. I remove serviceRunner

my srcond example code app.py:

from nameko.rpc import rpc


class ServiceA
    name = "service_a"
    @rpc
    def x(self):
        return "A"


class ServiceB
    name = "service_b"
    @rpc
    def x(self):
        return "B"

And exec nameko run --config test.yaml app again:

All okay, only two connections to RabbitMQ

starting services: service_a, service_B
Connected to amqp://quest:**@192.168.1.42:5672//
Connected to amqp://quest:**@192.168.1.42:5672//

Now the question. As far as I can see the ServiceA and SerivceB connects twice: from import and in serviceRunner
How to properly use the serviceRunner?

requirements.txt

amqp==2.4.0
certifi==2018.11.29
chardet==3.0.4
dnspython==1.16.0
eventlet==0.24.1
greenlet==0.4.15
idna==2.8
importlib-metadata==0.8
kombu==4.2.2.post1
limits==1.3
mock==2.0.0
monotonic==1.5
nameko==2.11.0
path.py==11.5.0
pbr==5.1.1
pika==0.13.0
PyYAML==3.13
requests==2.21.0
six==1.12.0
urllib3==1.24.1
vine==1.2.0
Werkzeug==0.14.1
wrapt==1.11.1
zipp==0.3.3

Hey @staskuban,

The ServiceRunner is intended to be used when you don’t use nameko run. A common use-case is creating your own application that wraps a service runner, for example to so some pre-processing before the Nameko service starts running.

It’s a little surprising that combining the two approaches just duplicates the runners.

Your second approach is the correct way to use nameko run – define your services in a module and ask the CLI to run it. The two connections you see are expected – there is one from each service.

As an aside, in production I recommend running each service in its own process (i.e. one service per runner)

Does that answer your question?

Matt.

Thanx @mattbennett!

At the moment I am producing a refactor of my service and I want to temporarily use 2 services in one serviceRunner: a service that implements business logic and public API, which will work until I implement a new transport.

I tried start runner via python app.py but its not working (crash with Process finished with exit code 134 (interrupted by signal 6: SIGABRT))

Сan provide any simple example for correct serviceRunner usage?

Can you share what’s in app.py?

The “correct” way to use the ServiceRunner is basically what you have in your first post, except you should execute it simply with python and not nameko run.

For more detail, study the nameko.cli.run module (which is where nameko run is implemented). In brief it does the following:

  • Discover services
  • Create a ServiceRunner and pass them to it
  • Applies the eventlet monkeypatch
  • Parses the config file
  • Sets up the backdoor, if requested
  • Adds signal handlers