Skip to main content

service framework supporting multiplemessaging and RPC implementations

Project description

https://secure.travis-ci.org/onefinestay/nameko.png?branch=master

Nameko [nah-meh-koh] (noun)

  1. amber-brown mushroom with a slightly gelatinous coating that is used as an ingredient in miso soup and nabemono.

  2. python services framework on top of AMQP

Getting Started

Nameko makes writing services easier by taking care of lifecycle management and interface plumbing. Just declare your dependencies, specify a configuration and write your business logic.

Let’s create a simple example.

We’ll start with service that prints “Hello World” when it receives an event. Here’s the business logic:

class HelloWorld(object):

    def hello(self, name):
        print "Hello, {}!".format(name)

To make it respond to an event, we have to make hello an event handler:

from nameko.events import event_handler

class HelloWorld(object):

    @event_handler('friendlyservice', 'hello')
    def hello(self, name):
        print "Hello, {}!".format(name)

Now, whenever a “friendlyservice” fires a “hello” event, hello will be called. Let’s create FriendlyService now:

 from nameko.events import Event, EventDispatcher
 from nameko.timer import timer

 class HelloEvent(Event):
     type = "hello"

class FriendlyService(object):

    name = "friendlyservice"
    dispatch = EventDispatcher()

    @timer(interval=5)
    def say_hello(self):
        self.dispatch(HelloEvent(self.name))

Using the nameko timer, instances of FriendlyService dispatch a hello event every 5 seconds. Let’s use nameko to make these two services interact:

from nameko.runners import ServiceRunner

config = {'AMQP_URI': 'amqp://guest:guest@localhost:5672/'}
runner = ServiceRunner(config)
runner.add_service(HelloWorld)
runner.add_service(FriendlyService)
runner.start()
try:
    runner.wait()
except KeyboardInterrupt:
    runner.kill()

RPC Example

Nameko comes with RPC support out of the box. To expose a method over RPC, decorate it with @rpc.

Adder service:

from nameko.rpc import rpc

class AdderService(object):

    @rpc
    def add(self, x, y):
        return x + y

If your service needs to call an RPC method in another service, you can use the Service proxy to access it.

Adder client:

import random

from nameko.rpc import rpc, Service
from nameko.timer import timer


class RpcClient(object):

    adder = Service('adderservice')

    @timer(interval=2)
    def add(self):
        x = random.randint(0, 10)
        y = random.randint(0, 10)
        res = self.adder.add(x, y)
        print "{} + {} = {}".format(x, y, res)

Messaging Example

Underlying the RPC and Events features shown above is the lower-level “messaging” codebase. You can use the messaging features to publish to and consume from AMQP directly.

demo_ex = Exchange('demo_ex', durable=False, auto_delete=True)
demo_queue = Queue('demo_queue', exchange=demo_ex, durable=False,
                   auto_delete=True)

class MessagingPublisher(object):
    """ Publish messages to the ``demo_ex`` exchange every two seconds.
    """
    publish = Publisher(exchange=demo_ex)

    @timer(interval=2)
    def send_msg(self):
        msg = "log-{}".format(uuid.uuid4())
        self.publish(msg)

class MessagingConsumer(object):
    """ Consume messages from a queue bound to the ``demo_ex`` exchange.
    """
    @consume(demo_queue)
    def process(self, payload):
        print payload

Dependencies

In the code snippets above, the timer, consume and rpc decorators, and the Publisher, Service and EventDispatcher classes declare the dependencies of their service.

Declaring dependencies is how a bare class becomes a nameko service, and the dependencies are injected when the class is hosted.

Have a look at nameko.dependencies to see how nameko interfaces with declared dependencies.

Writing Dependency Providers

It’s easy to write your own dependencies. Choose to extend either InjectionProvider or EntrypointProvider, and implement the appropriate interface methods.

Here’s an example dependency that writes to a log file, making use of nameko’s lifecycle management to open, close and flush the file at apppropriate points.

class LogFile(InjectionProvider):

   # called at dependency creation time (i.e. service definition)
   def __init__(self, path):
      self.path = path

   # called when the service container starts
   def prepare(self, srv_ctx):
      self.file_handle = open(self.path, 'w')

   # called when the service container stops
   def stop(self, srv_ctx):
      self.file_handle.close()

   # called before this dependency's service handles any call
   def acquire_injection(self, worker_ctx):
      def log(msg):
         self.file_handle.write(msg + "\n")
      return log

   # called after this dependency's service handles a call
   def release_injection(self, worker_ctx):
      self.file_handle.flush()

Moving the ‘plumbing’ into a dependency means that service developers can concentrate on the business logic of their code, and fosters a write-once, use-many-times philosophy.

To incorporate this dependency into our MessagingConsumer, we’d do this:

class MessagingConsumer(object):

    log = LogFile('/var/log/nameko.log')

    @consume(demo_queue)
    def process(self, payload):
        self.log(payload)

Working examples of the above can be found in docs/examples.

License

Apache 2.0. See LICENSE for details.

Project details


Release history Release notifications | RSS feed

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

nameko-1.0.0.tar.gz (44.6 kB view hashes)

Uploaded Source

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page