Skip to main content

Language-agnostic microservices boilerplate as a code

Project description

Language-agnostic microservices boilerplate as a code. You define service configuration and implementation, Harness takes care for it’s life cycle:

  • load configuration: read, validate
  • initialize environment: database and other outgoing connections
  • start servers/subscribers
  • graceful shutdown

Configuration

Harness uses Protocol Buffers as a configuration definition language (svc.proto file):

syntax = "proto3";

package cafe;

import "harness/options.proto";
import "harness/postgres.proto";
import "harness/grpc.proto";

message Configuration {
  bool debug = 1;
  harness.postgres.DSN db = 2 [(harness.options).input = "python/asyncpg.v1:Connection"];
  harness.grpc.Channel taskqueue = 3 [(harness.options).input = "python/grpclib.v1:Channel"];
  harness.grpc.Endpoint listen = 4 [(harness.options).output = "python/grpclib.v1:Server"];
}

As you can see from this configuration, our service has:

  • debug mode
  • database connection
  • gRPC channel to the taskqueue service
  • gRPC server to serve incoming requests

We can provide values for this configuration using YAML file (config.yaml file):

db:
  value: postgres://postgres:postgres@db.cafe.svc.cluster.local:5432/coffee
taskqueue:
  host: taskqueue.platform.svc.cluster.local
  port: 50051
listen:
  host: 0.0.0.0
  port: 50051

Service Definition

Harness must be able to run your service. In order to do this you must provide a main function, it’s signature looks like this:

from svc_wires import WiresIn, WiresOut

async def main(wires_in: WiresIn) -> WiresOut:
    ...
    return WiresOut(...)

Where WiresIn and WiresOut are generated by the Harness from your service configuration:

@dataclass
class WiresIn:
    db: harness.resources.asyncpg.v1.Connection
    taskqueue: harness.resources.grpclib.v1.Channel

@dataclass
class WiresOut:
    listen: harness.resources.grpclib.v1.Server

When Harness runs your service, you receive already initialized environment in a WiresIn structure. All you have to do is to setup your request handler and return it with a WiresOut structure (svc.py file):

from harness.resources.grpclib.v1 import Server

from svc_grpc import CoffeeMachineBase

class CoffeeMachine(CoffeeMachineBase):
    ...

async def main(wires_in: WiresIn) -> WiresOut:
    print('Connection:', wires_in.db.connection)
    print('Channel:', wires_in.taskqueue.channel)
    server_resource = Server([
        CoffeeMachine(
            db=wires_in.db.connection,
            taskqueue=wires_in.taskqueue.channel,
        ),
    ])
    return WiresOut(listen=server_resource)

Files Generation

We use protoc compiler to generate boilerplate from your configuration:

$ protoc -I $HARNESS_PROTO --python_out=. --python_grpc_out=. --python_harness_out=. --mypy_out=. svc.proto

Where $HARNESS_PROTO is where to find Harness proto-files.

Runtime

Use harness command to run your service:

$ harness svc:main config.yaml

Project details


Download files

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

Files for harness, version 0.1.0rc2
Filename, size File type Python version Upload date Hashes
Filename, size harness-0.1.0rc2.tar.gz (9.2 kB) File type Source Python version None Upload date Hashes View hashes

Supported by

Elastic Elastic Search Pingdom Pingdom Monitoring Google Google BigQuery Sentry Sentry Error logging AWS AWS Cloud computing DataDog DataDog Monitoring Fastly Fastly CDN DigiCert DigiCert EV certificate StatusPage StatusPage Status page