Skip to main content

Python 3 microservice library / framework using asyncio with HTTP, websockets, RabbitMQ / AMQP and AWS SNS+SQS support.

Project description

``tomodachi`` - a lightweight microservices framework with asyncio
==================================================================
A Python 3 microservice framework using asyncio (async / await) with HTTP,
websockets, RabbitMQ / AMQP and AWS SNS+SQS built-in support for event based
messaging and intra-service communication.

.. image:: https://travis-ci.org/kalaspuff/tomodachi.svg?branch=master
:target: https://travis-ci.org/kalaspuff/tomodachi
.. image:: https://img.shields.io/pypi/v/tomodachi.svg
:target: https://pypi.python.org/pypi/tomodachi
.. image:: https://codecov.io/gh/kalaspuff/tomodachi/branch/master/graph/badge.svg
:target: https://codecov.io/gh/kalaspuff/tomodachi
.. image:: https://img.shields.io/pypi/pyversions/tomodachi.svg
:target: https://pypi.python.org/pypi/tomodachi

Tomodachi is a tiny framework designed to build fast microservices listening on
HTTP or communicating over event driven message buses like RabbitMQ, AMQP,
AWS (Amazon Web Services) SNS+SQS, etc. It's designed to be extendable to make
use of any type of transport layer available.

*Tomodachi* [**友達**] *means friends – a suitable name for microservices working
together.* 😻 👬 👭 👫 😻


| **Please note: this is a work in progress.**
``tomodachi`` is still a highly experimental project with an unregular release
schedule.


Usage
-----
``tomodachi`` is invoked via command line interface.

.. code::

Usage: tomodachi <subcommand> [options] [args]

Options:
-h, --help show this help message and exit
-v, --version print tomodachi version
--dependency-versions print versions of dependencies

Available subcommands:
run <service ...> [-c <config-file ...>] [--production]
-c, --config <files> use json configuration files
-l, --log <level> specify log level
--production disable restart on file changes


How do I use this?
------------------
Preferrably installation should be done via ``pip`` to get the cli alias set
up automatically. Locally it is recommended to install ``tomodachi`` into a
virtualenv to avoid random packages into your base site-packages.

.. code:: bash

local ~$ pip install tomodachi


Basic HTTP based service 🌟
^^^^^^^^^^^^^^^^^^^^^^^^^^^
*Code for a simple service which would service data over HTTP.*

.. code:: python

import tomodachi

@tomodachi.service
class Service(object):
name = 'example'

# Request paths are specified as regex for full flexibility
@tomodachi.http('GET', r'/resource/(?P<id>[^/]+?)/?')
async def resource(self, request, id):
# Returning a string value normally means 200 OK
return 'id = {}'.format(id)

@tomodachi.http('GET', r'/health')
async def health_check(self, request):
# Return can also be a tuple, dict or even an aiohttp.web.Response
# object for more complex responses - for example if you need to
# send byte data, set your own status code or define own headers
return {
'body': 'Healthy',
'status': 200
}

# Specify custom 404 catch-all response
@tomodachi.http_error(status_code=404)
async def error_404(self, request):
return 'error 404'


RabbitMQ or AWS SNS/SQS event based messaging service 📡
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
*Example of a service that would invoke a function when messages are published on a topic exchange.*

.. code:: python

import tomodachi

@tomodachi.service
class Service(object):
name = 'example'

# A route / topic on which the service will subscribe to via AMQP (or AWS SNS/SQS)
@tomodachi.amqp('example.topic')
async def example_topic_func(self, message):
# Received message, sending same message as response on another route / topic
await tomodachi.amqp_publish(self, message, routing_key='example.response')


Run the service 😎
------------------
.. code:: bash

  # cli alias is set up if installed via pip
  local ~/src/service$ tomodachi run service.py

# example if cloned from repo
local ~/src/tomodachi$ python tomodachi.py run example/http_service.py


*Defaults to output information on stdout.*

.. code:: console

  $ tomodachi run service.py

tomodachi/X.X.XX
October 02, 2017 - 13:38:00,481516
Quit services with <ctrl+c>.
2017-10-02 13:38:01,234 (services.service): Initializing service "example" [id: <uuid>]
2017-10-02 13:38:01,248 (transport.http): Listening [http] on http://127.0.0.1:9700/
2017-10-02 13:38:01,248 (services.service): Started service "example" [id: <uuid>]


*HTTP service acts like a normal web server.*

.. code:: console

$ curl -v "http://127.0.0.1:9700/resource/1234"

< HTTP/1.1 200 OK
< Content-Type: text/plain; charset=utf-8
< Server: tomodachi
< Content-Length: 9
< Date: Mon, 02 Oct 2017 13:38:02 GMT
id = 1234


Requirements 👍
---------------
* Python_ 3.5.3+, 3.6+
* aiohttp_
* aiobotocore_
* aioamqp_
* ujson_
* uvloop_

.. _Python: https://www.python.org
.. _asyncio: http://docs.python.org/3.5/library/asyncio.html
.. _aiohttp: https://github.com/aio-libs/aiohttp
.. _aiobotocore: https://github.com/aio-libs/aiobotocore
.. _aioamqp: https://github.com/Polyconseil/aioamqp
.. _ujson: https://github.com/esnme/ultrajson
.. _uvloop: https://github.com/MagicStack/uvloop


License 🙋
----------
Offered under the `MIT license <https://github.com/kalaspuff/tomodachi/blob/master/LICENSE>`_


Source code 🦄
--------------
The latest developer version of tomodachi is available at the GitHub repo https://github.com/kalaspuff/tomodachi


Any questions?
==============
What is the best way to run a tomodachi service?
There is no way to tell you how to orchestrate your infrastructure. Some people may run it containerized in a Docker environment, deployed via Terraform and some may run several services on the same environment, on the same machine. There are no standards and we're not here to tell you about your best practices.

Are there any more example services?
There are a few examples in the `examples <https://github.com/kalaspuff/tomodachi/blob/master/examples>`_ folder, including examples to publish events/messages to an AWS SNS topic and subscribe to an AWS SQS queue. There's also a similar example of how to work with pub-sub for RabbitMQ via AMQP transport protocol.

Why should I use this?
I'm not saying you should, but I'm not saying you shouldn't. ``tomodachi`` is a perfect place to start when experimenting with your architecture or trying out a concept for a new service. It may not have all the features you desire and it may never do.

Should I run this in production?
It's all still highly experimental and it depends on other experimental projects, so you have to be in charge here and decide for yourself. Let me know if you do however!

Who built this and why?
My name is **Carl Oscar Aaro** and I'm a coder from Sweden. I simply wanted to learn more about asyncio and needed a constructive off-work project to experiment with – and here we are. 🎉

Changes
=======

0.10.0 (2018-04-20)
-------------------
- Base example message protocol class for using Protocol Buffers over AMQP
or AWS SNS+SQS. (github: **smaaland**).

- Validation of event based messages via validation function specified
during decoration. (github: **smaaland**)

- Updates to work with ``aiohttp`` 3.1.X+.

- Improved logging functionality.

- Better type hinting and linting.


0.9.5 (2018-03-16)
------------------
- More robust handling of invoking service files that aren't a part of a
Python package.


0.9.4 (2018-03-06)
------------------
- Fixes an issue affecting websocket connections where the receive function
was invalidly called twice of which one time were without error handling.


0.9.3 (2018-03-06)
------------------
- Solves an error with functions for AMQP / AWS SNS+SQS functions that are used
without a message_protocol class.

- Improved disconnect and reconnect to AWS SNS+SQS via aiobotocore on hot-reload
and during testing.

- Improved README with event based messaging example using AMQP.

- Added the option of running ``schedule`` tasks immediately on service start.
For example a function decorated by
``@schedule(interval=20, immediately=True)`` would be run immediately on
service start and then every 20 seconds.


0.9.2 (2018-03-05)
------------------
- Improved error handling for bad requests (error 400) on HTTP calls.

- File watcher for hot-reload now excludes ignored directories in a more
effective way to ease CPU load and for faster boot time for projects
with thousands of files which should've been ignored.


0.9.1 (2018-03-05)
------------------
- ``schedule`` functions limits to 20 running tasks of the same function to
prevent overflows in development.

- Fixes an issue where ``schedule`` tasks stopped executing if a service was
hot-reloaded on code change.

- Handles websocket cancellations better if the client would close the
connection before the request had been upgraded.


0.9.0 (2018-03-04)
------------------
- Updated to use ``aiohttp`` 3.X.X+ and ``aiobotocore`` 0.6.X+.

- Dropped support for Python versions below 3.5.3 as new ``aiohttp`` requires
at least Python 3.5.3. Last version with support for Python 3.5.0, 3.5.1 and
3.5.2 is ``tomodachi`` ``0.8.X`` series.


0.8.3 (2018-03-02)
------------------
- Print stack trace for outputs from ``schedule`` invoker functions tasks
instead of silently catching exceptions.

- Handle close and receive errors for websockets and cleanly close already
opened websockets on service exit.


0.8.2 (2018-02-28)
------------------
- Fixed broken HTTP transports due to missing colorama import.


0.8.1 (2018-02-27)
------------------
- Correction for README in 0.8.X release.


0.8.0 (2018-02-27)
------------------
- It's now possible to specify queue_name on AWS SNS+SQS and AMQP decorators
for competing queues. If not specified an automatically generated hash will
be used as queue name as it worked previously.

- Fixes an issue with relative imports from within service files, which
resulted in "SystemParent module '' not loaded, cannot perform relative
import" or "ImportError: attempted relative import with no known parent
package". (github: **0x1EE7**)

- Exceptions that are subclasses of ``AmqpInternalServiceError`` and
``AWSSNSSQSInternalServiceError`` will now also work in the same way,
resulting in the messages to be retried when raised.

- Service classes now have built in log functions for setting up logging to
file as well as logging. They are ``self.log_setup('logname', level,
filename)`` and ``self.log('logname', level, message)``.

- HTTP services will have their access log color coded when outputting to
nothing else than stdout, which should be helpful in an overview during
development.


0.7.0 (2018-01-27)
------------------

- Added `@websocket` as a decorator type for handling websockets. A function
call should return two callables which will be used for receiving messages
through the socket and as a way to notify about the closure of the socket.


0.6.5 (2018-01-16)
------------------

- Updated `aiohttp` to latest version which solves incompabilities with `yarl`.


0.6.4 (2018-01-15)
------------------

- Added a stricter dependency check for `yarl`.


0.6.3 (2018-01-12)
------------------

- Gracefully handle exceptions thrown when receiving messages from AWS SNS+SQS.
For example when invalid XML data in response which causes botocore to throw
a botocore.parsers.ResponseParserError.

- Updated dependencies to allow for newer version of aiohttp 2.3.X.

- Improved type hinting.


0.6.2 (2017-11-15)
------------------

- Recreate queues and resubscribe to topics if queue is removed during runtime.


0.6.1 (2017-11-15)
------------------

- Introduced new options for AWS SNS/SQS transport to use `aws_endpoint_urls`
for `sns` and `sqs` if the user wishes to connect to other endpoints and the
actual AWS endpoints, which could be useful for development and testing. The
AWS SNS/SQS examples has been updated with values to reflect these options.

- Reworked timeouts and reconnects and fixed an issue in the recreate_client
method which was called on server disconnects.


0.6.0 (2017-11-15)
------------------

- Stricter version control of required packages to not break installation on
major/minor related updates.

- Updates to support aiohttp 2.3.X and aiobotocore 0.5.X.


0.5.3 (2017-11-08)
------------------

- Corrects issues on timeouts and server disconnects.

- Specify fixed version for aiohttp to not break installation.

- Code cleanup to conform with pycodestyle.


0.5.2 (2017-10-08)
------------------

- Add argument option for log level as '-l' or '--log'. (github: **djKooks**)

- Better matching of imported modules on hot-reload which will cause reloading
into code with syntax errors or indentation errors much harder.


0.5.1 (2017-10-03)
------------------

- More improvements regarding hot-reloading of code that may have syntax errors,
indentation errors or issues when the service is being initiated.


0.5.0 (2017-10-02)
------------------

- Solves the issue where hot-loading into a state where the code errors due to
syntax errors would crash the application, making the user need to manually
restart the process.


0.4.10 (2017-10-02)
-------------------

- Fixes for failing tests on hot-reloading during test phase.


0.4.9 (2017-10-02)
------------------

- Solves issue with Segmentation fault in Python 3.6 during hot-reload on
Linux.


0.4.8 (2017-10-02)
------------------

- Fixes type hinting issues with Python 3.5.1.


0.4.7 (2017-09-30)
------------------

- Reworked watcher since it ended up using 90% CPU of the running core due to
constant re-indexing (mstat) of every file every 0.5s. Full re-index will now
only run every 10 seconds, since it's more rare that new files are added than
existing files edited. Watcher for edited existing files will still run at the
same intervals.

- Watched file types may now be specified via configuration via
``options.watcher.watched_file_endings``.


0.4.6 (2017-09-29)
------------------

- Messages via SNS+SQS or AMQP over 60000 bytes as JSON will now be sent in a
gzipped base64 encoded format to allow for larger limits and lower potential
SNS costs due to multiplexed messaging.

- Fixes an issue with multidict 3.2.0 on hot-reload which made the tomodachi
application crash.


0.4.5 (2017-09-07)
------------------

- Possibility to requeue messages that result in specific exceptions.
Exceptions that will nack the message (for AMQP transport) is called
``AmqpInternalServiceError``. Exceptions that won't delete the message from
the queue and in turn will result in it to "reappear" unless configured
non-default (for AWS SNS+SQS transport) is called
``AWSSNSSQSInternalServiceError``.


0.4.4 (2017-08-25)
------------------

- Corrected an issue regarding crontab notation for scheduling function calls
where it didn't parse the upcoming date correctly if both isoweekday and day
part were given.


0.4.3 (2017-08-09)
------------------

- Catches unintended HTTP exceptions and prints a useful stacktrace if log_level
is set to DEBUG.


0.4.2 (2017-08-07)
------------------

- Fixes an issue where Content-Type header couldn't be specified without
charset in HTTP transports.

- Cleared some old debug code.


0.4.1 (2017-08-05)
------------------

- Corrects and issue with AMQP transport which caused invoked functions to not
be able to declare scope variables without crashes.


0.4.0 (2017-08-05)
------------------

- Release fixes a major issue which caused invoked functions to not be able to
declare any scope variables.

- ``@http_static`` decorator for serving static files from a folder on disk.
Takes to values; 1. the path to the folder, either relative to the service
file or absolute; 2. the base URL path for static files as a regexp.


0.3.0 (2017-07-25)
------------------

- Changed format of access log for HTTP requests - now logging user agent and
login name (if authorization via Basic Auth).

- Support for ``X-Forwarded-For`` headers via ``real_ip_from`` and
``real_ip_header`` options which will log the forwarded IP instead of the
one from the load balancer / proxy.

- Access log for HTTP can now be specified as a filename to which the service
will log all requests.

- Fixes issue with schedule invoker which would crash if invoked at second 0.

- Updated dependencies to latest available versions.


0.2.17 (2017-07-05)
-------------------

- Timezone support for ``schedule`` invoker functions.

- Added more decorator invoker functions as aliases for common scheduler
use cases - ``@minutely``, ``@hourly``, ``@daily`` and ``@heartbeat`` (every
second)

- Updated example services and better test cases.

- Updated aiohttp / aiobotocore / botocore dependencies.


0.2.16 (2017-07-02)
-------------------

- Solved issues with aiobotocore / aiohttp dependencies.

- Refactored loader functions.


0.2.15 (2017-07-02)
-------------------

- Corrected issue with configuration values for AWS and AWS SNS+SQS settings.

- Improved testing suite and more code coverage for integration tests.


0.2.14 (2017-06-30)
-------------------

- New "transport" invoker for service functions: ``schedule``. It works like
cron type scheduling where specific functions will be run on the specified
interval. For example a function can be specified to run once per day at a
specific time or every second minute, or the last Tuesday of January and
March at 05:30 AM.

- Values for keyword arguments invoked by transport decorators were earlier
always set to ``None``, despite having other default values. This is now
corrected.


0.2.13 (2017-06-20)
-------------------

- Type hinted examples and test cases.

- Shielded function calls for AMQP and SNS+SQS transports to avoid unexpected
execution stop.

- Added version output to tomodachi CLI tool.

- Additional test cases.


0.2.12 (2017-06-18)
-------------------

- Type hinted code base and minor bug fixes for internal functions.


0.2.11 (2017-06-09)
-------------------

- Invoker methods can now be called directly without the need to mock the
invoker decorator function.


0.2.10 (2017-06-08)
-------------------

- Added ``@functools.wraps`` decorator to invoked functions of service classes.


0.2.9 (2017-06-06)
------------------

- Added a list of safe modules that may never be removed from the list of
already loaded modules. Removing the module 'typing' from the list would
cause a RecursionError exception since Python 3.6.1.


0.2.8 (2017-05-23)
------------------

- Additional improvements to network connectivity issues to not get stuck in
waiting state.


0.2.7 (2017-05-23)
------------------

- Improved SNS+SQS draining / restart when network connectivity has been lost
or temporarily suspended. Would improve situations when development machine
has been in hibernation.

- Replaced deprecated logging functions to rid warnings.


0.2.6 (2017-05-22)
------------------

- Support for a "generic" aws dictonary in options that can hold region,
access key id and secret to be shared among other AWS resources/services.

- Updated aiobotocore / botocore dependencies.

- Gracefully handle and discard invalid SNS/SQS messages not in JSON format.

- Corrected issue where watched directories with "similar" names as settings
would be ignored.


0.2.5 (2017-05-16)
------------------

- Updated issues with function caching due to keepalive when hot reloading in
development. Currently disables keepalive entirely.

- Fixed issue with updated file logging for watcher.


0.2.4 (2017-05-12)
------------------

- Downgraded botocore to meet requirements and to make the installed
``tomodachi`` script runnable again.


0.2.3 (2017-05-10)
------------------

- Watcher is now configurable to ignore specific directories dependant on the
service. (github: **smaaland**)

- Fixed issue where using ``--config`` instead of ``-c`` would result in a
raised exception. (github: **smaaland**)


0.2.2 (2017-05-04)
------------------

- ``tomodachi.transport.http`` has its own Response object that works better
with default content types and charsets - examples/http_service.py updated.

- No automatic conversion will be tried if the returned response of an http
method is of ``bytes`` type.

0.2.1 (2017-05-03)
------------------

- Improved handling of how charsets and encodings work with aiohttp.

- Fixed an issue where ``Content-Type`` header would always be included twice
for aiohttp.web.Response objects.


0.2.0 (2017-05-02)
------------------

- Watcher now only reacts to files with file endings ``.py``, ``.json``,
``.yml``, ``.html`` or ``.html`` and ignores to look at paths
``__pycache__``, ``.git``, ``.svn``, ``__ignored__``, ``__temporary__`` and
``__tmp__``.

- HTTP transport may now respond with an aiohttp.web.Response object for more
complex responses.

- HTTP transport response headers can now use the multidict library.


0.1.11 (2017-04-02)
-------------------

- Working PyPI release.

- Added unit tests.

- Works with aiohttp 2 and aiobotocore 0.3.

- Service classes must be decorated with ``@tomodachi.service``.

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

tomodachi-0.10.0.tar.gz (50.7 kB view hashes)

Uploaded Source

Built Distribution

tomodachi-0.10.0-py3-none-any.whl (59.0 kB view hashes)

Uploaded Python 3

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