Giter Club home page Giter Club logo

asab's Introduction

Asynchronous Server App Boilerplate

https://travis-ci.com/TeskaLabs/asab.svg?branch=master https://img.shields.io/github/license/TeskaLabs/asab https://readthedocs.org/projects/asab/badge/?version=latest

Asynchronous Server App Boilerplate (or ASAB for short) is a microservice framework for Python 3 and asyncio. The aim of ASAB is to minimize the amount of code that needs to be written when building a microservice or an aplication server. ASAB is fully asynchronous using async/await syntax from Python 3, making your code modern, non-blocking, speedy and hence scalable. We make every effort to build ASAB container-friendly so that you can deploy ASAB-based microservice via Docker or Kubernetes in a breeze.

ASAB is the free and open-source software, available under BSD licence. It means that anyone is freely licenced to use, copy, study, and change the software in any way, and the source code is openly shared so that people could voluntarily improve the design of the software. Anyone can (and is encouraged to) use ASAB in his or her projects, for free.

ASAB is currently used for microservices, web application servers, ETL or stream processors.

ASAB is developed on GitHub. Contributions are welcome!

Installation

$ pip install asab

Documentation

Example

#!/usr/bin/env python3
import asab.web.rest

class MyApplication(asab.Application):

    def __init__(self):
        super().__init__()

        # Create the Web server
        web = asab.web.create_web_server(self)

        # Add a route to the handler method
        web.add_get('/hello', self.hello)

    # This is the web request handler
    async def hello(self, request):
        return asab.web.rest.json_response(request, data="Hello, world!\n")

if __name__ == '__main__':
    # Create and start the application
    app = MyApplication()
    app.run()

The application is available at http://localhost:8080/. You can test it by:

$ curl http://localhost:8080/hello

Microservices

Here is a growing list of Open Source microservices built using ASAB:

  • ASAB Iris: document rendering, sends output using email, SMS and instant messaging
  • SeaCat Auth: authentication, authorization, identity management, session management and other access control features

Highlights

  • Unified approach to Configuration
  • Logging using reasonably configured Python logging module
  • Build-in and custom Metrics with feeds into InfluxDB and Prometheus
  • Alerting with integration to PagerDuty and OpsGenie.
  • HTTP Server powered by aiohttp library
  • Apache Zookeeper Client provides shared consensus across microservices’ cluster
  • Persistent storage abstraction based on upsertor for MongoDB and ElasticSearch
  • Pub/Sub
  • Dependency injection using Modules and Services
  • Proactor pattern service for long-running synchronous work
  • Task service
  • Unified microservice API

Automatic API documentation

The REST API is automatically documented using OpenAPI3 standard and the Swagger.

https://github.com/TeskaLabs/asab/raw/master/doc/openapi3-swagger.jpg

Principles

  • Write once, use many times
  • Keep it simple
  • Well documented
  • Asynchronous via Python 3 async/await and asyncio
  • Event-driven Architecture / Reactor pattern
  • Single-threaded core but compatible with threads
  • First-class support for containerization
  • Compatible with pypy, Just-In-Time Python compiler
  • Kappa architecture
  • Support for introspection
  • Modularized

Video tutorial

http://img.youtube.com/vi/77StpWxOIBc/0.jpg

Licence

ASAB is an open-source software, available under BSD 3-Clause License. ASAB is maintained by TeskaLabs Ltd.

asab's People

Contributors

antoninvf avatar ateska avatar avglassman avatar awichera avatar bochkver avatar byewokko avatar eliska-n avatar gitter-badger avatar jsafranek avatar kanospet avatar kaymine avatar language-shprt avatar margirova avatar martinkubajda avatar mejroslav avatar mithunbharadwaj avatar mpavelka avatar pe5h4 avatar plesoun avatar premyslcerny avatar sedoy26 avatar sukicz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

asab's Issues

Extend support for the InfluxDB v2 API

The InfluxDB API has been obviously evolved, so we need to reflect that as well.

https://docs.influxdata.com/influxdb/v2.1/api/#tag/Write

self.WriteRequest = '/write?db={}'.format(self.Config.get('db'))

  • New configuration options should be added:
  • org
  • bucket
  • orgID

User can specify the db or org + bucket + (optionally) orgId.

  • Configuration to support also token

If provided, then it should be used as header: Authorization: Token YOUR_INFLUX_TOKEN

https://docs.influxdata.com/influxdb/v2.1/api/#tag/Authentication

Example

[asab.metrics]
target=influxdb
org=your_org
bucket=your_bucket
token=YOUR_INFLUX_TOKEN

DeprecationWarning / asyncio.Event(loop=self.Loop)

Refactor this:

/Users/ateska/Workspace/splang/sp-lang/asab/application.py:121: DeprecationWarning: The loop argument is deprecated since Python 3.8, and scheduled for removal in Python 3.10.

self._stop_event = asyncio.Event(loop=self.Loop)

https://docs.python.org/3/library/asyncio-sync.html#asyncio.Event

Deprecated since version 3.8, removed in version 3.10: The loop parameter. This class has been implicitly getting the current running loop since 3.7. See What’s New in 3.10’s Removed section for more information.

Automatic TCP port allocation for ASAB API

This becomes handy when multiple ASAB-based microservices are deployed in the "network: host" mode e.g. in a Docker.
The API port is to be assigned by OS and eventually advertised via e.g. Zookeeper into a common directory.

Zookeeper part is optional for now.

Notation:

0.0.0.0:auto (the auto part is important)

ASAB change dir after daemonize

Clarify on how ASAB handles change dir after daemonization b/c it differs from a command-line (foreground) mode - and it can lead to confusion.

I want to be able to extend the AccessLogger in a WebContainer

In the following code of a WebContainer, an AccessLogger is provided to aiohttp.web.AppRunner:

self.WebAppRunner = aiohttp.web.AppRunner(
	self.WebApp,
	handle_signals=False,
	access_log=logging.getLogger(__name__[:__name__.rfind('.')] + '.al'),
	access_log_class=AccessLogger,
)

self.WebAppRunner = aiohttp.web.AppRunner(

As a developer I want to be able to extend the AccessLogger so that I can enrich structured data in the access log (for example with an identityId).

ZK wrapper Error messages

L.warning("Getting the data failed.git")

These error messages are very general and do not indicate what is the problem even though they catch specifically NoNode Error. It would be friendly to say that there is no node and pass the path string also into the message.

No default ZK config 2

'providers': 'zk://zookeeper-1:2181/library'

Got this error outside of lmio-testing:

Traceback (most recent call last):
  File "/opt/remote-control/remote_control.py", line 5, in <module>
    app = remote_control.RemoteControlApp()
  File "/usr/lib/python3.8/site-packages/asab/abc/singleton.py", line 14, in __call__
    cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
  File "/opt/remote-control/remote_control/app.py", line 27, in __init__
    self.ZooKeeperContainer = asab.zookeeper.ZooKeeperContainer(self.ZooKeeperService, config_section_name='zookeeper')
  File "/usr/lib/python3.8/site-packages/asab/zookeeper/container.py", line 47, in __init__
    self.ZooKeeper = KazooWrapper(zksvc.App, self.Config, z_path)
  File "/usr/lib/python3.8/site-packages/asab/zookeeper/wrapper.py", line 81, in __init__
    self.Client = kazoo.client.KazooClient(hosts=url_netloc)
  File "/usr/lib/python3.8/site-packages/kazoo/client.py", line 223, in __init__
    self.set_hosts(hosts)
  File "/usr/lib/python3.8/site-packages/kazoo/client.py", line 461, in set_hosts
    self.hosts, chroot = collect_hosts(hosts)
  File "/usr/lib/python3.8/site-packages/kazoo/hosts.py", line 26, in collect_hosts
    raise ValueError("bad hostname")
ValueError: bad hostname
29-Jun-2022 14:17:16.071764 WARNING kazoo.client Cannot resolve zookeeper-1: [Errno -3] Try again

image

Add support for Prometheus OpenMetrics

ASAB metrics should be extended to provide ability to integrate with Prometheus, using OpenMetrics standard.

Specifically it means that ASAB API should:

  • add the new endpoint /asab/v1/metrics that communicates using OpenMetrics standard
  • this new endpoint should locate metrics service (it is optional!), iterate over .Metrics and prepare OpenMetrics output line for each metrics object

https://openmetrics.io

Example of the output:

# TYPE acme_http_router_request_seconds summary
# UNIT acme_http_router_request_seconds seconds
# HELP acme_http_router_request_seconds Latency though all of ACME's HTTP request router.
acme_http_router_request_seconds_sum{path="/api/v1",method="GET"} 9036.32
acme_http_router_request_seconds_count{path="/api/v1",method="GET"} 807283.0
acme_http_router_request_seconds_created{path="/api/v1",method="GET"} 1605281325.0
acme_http_router_request_seconds_sum{path="/api/v2",method="POST"} 479.3
acme_http_router_request_seconds_count{path="/api/v2",method="POST"} 34.0
acme_http_router_request_seconds_created{path="/api/v2",method="POST"} 1605281325.0
# TYPE go_goroutines gauge
# HELP go_goroutines Number of goroutines that currently exist.
go_goroutines 69
# TYPE process_cpu_seconds counter
# UNIT process_cpu_seconds seconds
# HELP process_cpu_seconds Total user and system CPU time spent in seconds.
process_cpu_seconds_total 4.20072246e+06
# EOF

Replace all `datetime.utcnow()` with `datetime.now(timezone.utc)`

*) datetime.datetime.utcnow().isoformat() + 'Z' construct is OK, add a comment that it is approved.

See https://docs.python.org/3/library/datetime.html#datetime.datetime.utcnow

Console logging

I can see that console logging is disabled when it is redirected. This is convenient for a service, but a problem when working in PyCharm. I would like to add a configuration entry or/and an option to force logging to console.

In-memory StorageService can't be instantiated because of missing implementation of get_by

inmemory is the default storage engine. The following code in asab/storage/__init__.py:

		if sttype == 'inmemory':
			from .inmemory import StorageService
			self.Service = StorageService(app, "asab.StorageService")

fails with TypeError: Can't instantiate abstract class StorageService with abstract methods get_by.

get_by must be implemented in asab/storage/inmemory.py in StorageService

Authn/authz using ID token

As an alternative to calling OpenID Connect /userinfo endpoint, the app should support authentication and authorization using JWT ID token.

Async tasks escape the initialization phase.

Tasks that are created inside an "initialize" lifecycle methods of Application (1) and/or Service (2) objects escape the initialization phase. Examples below have been tried with Python 3.6.7

1) In this example with Application object, do_sleep() runs out of the scope of the init phase if called using ensure_future():

import asab
import asyncio

class Application(asab.Application):

	def __init__(self):
		super().__init__()

	async def initialize(self):
		await self.do_sleep() # do_sleep happens during the init phase
		asyncio.ensure_future(self.do_sleep()) # do_sleep escapes the init phase

	async def do_sleep(self):
		print("Application: before sleep")
		await asyncio.sleep(2)
		print("Application: after sleep")

	async def main(self):
		print("MAIN!")
		self.stop()

def main():
	app = Application()
	app.run()

if __name__ == '__main__':
	main()

2) In this example with initialization of Service object it is so that do_sleep() doesn't run within the init phase in both cases - when called using await and/or when called using ensure_future()

import asab
import asyncio

class MyService(asab.Service):

	async def initialize(self, app):
		await self.do_sleep() # do_sleep() AND self.initialize() escape the init phase
		asyncio.ensure_future(self.do_sleep()) # do_sleep() escapes init phase

	async def do_sleep(self):
		print("MyService: before sleep")
		await asyncio.sleep(2)
		print("MyService: after sleep")


class Application(asab.Application):

	def __init__(self):
		super().__init__()
		MyService(self, "MyService")

	async def main(self):
		print("MAIN!")
		self.stop()

def main():
	app = Application()
	app.run()

if __name__ == '__main__':
	main()

Configuration of WebContainer's "listen" should support format "${host}:${port}" (with a colon)

When providing a command line argument for users to pass "listen" option in a custom application, the value must be wrapped in quotation marks, otherwise the value is not correctly parsed:

# Won't work:
app.py -l 0.0.0.0 8080
# Works:
app.py -l "0.0.0.0 8080"

By supporting the format with semicolon, users can omit the quotation marks:

app.py -l 0.0.0.0:8080
app.py -l [2001:db8:a::123]:8080

JSON Schema support for asab.web.rest

asab.web.rest should provide a convenient function for validating incoming JSON REST requests using JSON schema. https://json-schema.org

Example of use:

@asab.web.rest.json_schema_handler(my_schema)
async def login(self, request, *, json):
	...

Remarks:

The asab.mom should be taken in consideration as well.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.