Coder Social home page Coder Social logo

teskalabs / asab Goto Github PK

View Code? Open in Web Editor NEW
29.0 29.0 7.0 5.06 MB

Asynchronous Server App Boilerplate (ASAB) is a micro-service framework for Python 3 and asyncio.

Home Page: https://docs.teskalabs.com/asab/

License: BSD 3-Clause "New" or "Revised" License

Python 13.44% Dockerfile 0.03% Makefile 0.02% HTML 82.83% CSS 1.78% JavaScript 1.87% Shell 0.01% Batchfile 0.02%
asynchronous asyncio kappa-architecture microservice python3

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

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()

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

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.

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

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

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).

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

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.

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

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.

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)

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

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.

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.

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.

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.