Skip to main content

Simple Microservice Configuration

Well-written microservices are small and single-purpose; any non-trivial ecosystem will have a fleet of such services, each performing a different function. Inevitably, these services will use common code and structure; this library provides a simple mechanism for constructing these shared components and wiring them together into services.

Circle CI

Terminology

  • A microservice is a small software application. It is composed of several smaller pieces of software, many of which are reusable.
  • A component is one of these (possibly reusable) pieces of software.
  • A factory is a function used to create a component; it may be an object's constructor.
  • A config dict is a nested dictionary with string-valued keys. It contains data used by factories to create components.
  • An object graph is a collection of components that may reference each other (acyclically).
  • A binding is a string-valued key. It is used to identify a component within an object graph and the subsection of the config dict reserved for a component's factory.

Basic Usage

  1. Define factory functions for components, attach them to a binding, and provide (optional) configuration defaults:

    from microcosm.api import defaults, binding
    
    @binding("foo")
    @defaults(baz="value")
    def create_foo(graph):
        return dict(
            # factories can reference other components
            bar=graph.bar,
            # factories can reference configuration
            baz=graph.config.foo.baz,
        )
    
    @binding("bar")
    def create_bar(graph):
        return dict()
    

    Factory functions have access to the object graph and, through it, the config dict. Default configuration values, if provided, are pre-populated within the provided binding; these may be overridden from data loaded from an external source.

  2. Wire together the microservice by creating a new object graph along with service metadata:

    from microcosm.api import create_object_graph
    
    graph = create_object_graph(
        name="myservice",
        debug=False,
        testing=False,
    )
    

    Factories may access the service metadata via graph.metadata. This allows for several best practices:

    • Components can implement ecosystem-wide conventions (e.g. for logging or persistence), using the service name as a discriminator.
    • Components can customize their behavior during development (debug=True) and unit testing (testing=True)
  3. Reference any binding in the object graph to access the corresponding component:

    print(graph.foo)
    

    Components are initialized lazily. In this example, the first time graph.foo is accessed, the bound factory (create_foo()) is automatically invoked. Since this factory in turn accesses graph.bar, the next factory in the chain (create_bar()) would also be called if it had not been called yet.

    Graph cycles are not allowed, although dependent components may cache the graph instance to access depending components after initialization completes.

  4. Optionally, initialize the microservice's components explicitly:

    graph.use(
        "foo",
        "bar",
    )
    

    While the same effect could be achieved by accessing graph.foo or graph.bar, this construction has the advantage of initializes the listed components up front and triggering any configuration errors as early as possible.

    It is also possible to then disable any subsequent lazy initialization, preventing any unintended initialization during subsequent operations:

    graph.lock()
    

Assumptions

This library was influenced by the pinject project, but makes a few assumption that allow for a great deal of simplication:

  1. Microservices are small enough that simple string bindings suffice. Or, put another way, conflicts between identically bound components are a non-concern and there is no need for explicit scopes.

  2. Microservices use processes, not threads to scale. As such, thread synchronization is a non-goal.

  3. Mocking (and patching) of the object graph is important and needs to be easy. Unit tests expect to use `unittest.mock library; it should be trivial to temporarily replace a component.

  4. Some components will be functions that modify other components rather than objects that need to be instantiated.

Setup

Create a virtualenv

python -m venv venv
. ./venv/bin/activate

Install dependencies

pip install -U -e .

Tests

Run the tests

python setup.py nosetests

Lint

Lint the code:

NAME=microcosm ./entrypoint.sh lint
NAME=microcosm ./entrypoint.sh typehinting

Release files for microcosm 4.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for microcosm 4.1.0
File Size Uploaded
microcosm-4.1.0.tar.gz 25.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for microcosm 4.1.0
File Interpreter ABI Platform
microcosm-4.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 55.8 kB

Release files / microcosm-4.1.0.tar.gz

Download URL microcosm-4.1.0.tar.gz
Size 25.1 kB
Tags Source
SHA-256 checksum
How to use checksums
2d9297ffdd296d4ca96c81b6c96db6dfe89bf71371d5abf58865a0b699852279
BLAKE2b-256 checksum
How to use checksums
2311f1badbae3dc6ef64316ba6f00481a0a44d7515c3c560546964341eb4235e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/4.0.2 CPython/3.11.9

Release files / microcosm-4.1.0-py3-none-any.whl

Download URL microcosm-4.1.0-py3-none-any.whl
Size 30.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f85d7f60a388b5a2d59083c0fd5e9c120c44bfb3a779d62d1094f1bc37d6fae0
BLAKE2b-256 checksum
How to use checksums
6b469a113fa4b6412a170333c566707db642095c45a60eb2c1ea618e846d4c37
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/4.0.2 CPython/3.11.9

Release history Release notifications | RSS feed

This release

4.1.0 This release

2 release files

4.0.0

2 release files

3.5.1

1 release file

3.5.0

1 release file

3.4.0

1 release file

3.2.0

1 release file

3.1.0

1 release file

3.0.0

1 release file

2.14.0

1 release file

2.13.2

1 release file

2.13.1

1 release file

2.13.0

1 release file

2.12.2

1 release file

2.12.1

1 release file

2.12.0

1 release file

2.11.1

1 release file

2.11.0

1 release file

2.10.0

1 release file

2.9.0

1 release file

2.8.4

1 release file

2.8.3

1 release file

2.8.2

1 release file

2.7.0

1 release file

2.6.0

1 release file

2.5.0

1 release file

2.4.1

1 release file

2.4.0

1 release file

2.3.0

1 release file

2.2.0

1 release file

2.1.0

1 release file

2.0.0

1 release file

1.4.0

1 release file

1.3.2

1 release file

1.3.0

1 release file

1.2.0

1 release file

1.1.0

1 release file

1.0.0

1 release file

0.17.2

1 release file

0.17.1

1 release file

0.17.0

1 release file

0.16.0

1 release file

0.15.0

1 release file

0.14.0

1 release file

0.13.0

1 release file

0.12.0

1 release file

0.11.0

1 release file

0.10.0

1 release file

0.9.0

1 release file

0.8.0

1 release file

0.7.0

1 release file

0.6.0

1 release file

0.5.1

1 release file

0.5.0

1 release file

0.4.0

1 release file

0.3.0

1 release file

0.2.1

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page