aiomisc - miscellaneous utils for asyncio#
As a programmer, you are no stranger to the challenges that come with building and maintaining software applications. One area that can be particularly difficult is making architecture of the asynchronous I/O software.
This is where aiomisc
comes in. It is a Python library that
provides a collection of utility functions and classes for working with
asynchronous I/O in a more intuitive and efficient way. It is built on
top of the asyncio
library and is designed to make it easier for
developers to write asynchronous code that is both reliable and scalable.
With aiomisc
, you can take advantage of powerful features like
worker pools, connection pools,
circuit breaker pattern,
and retry mechanisms such as asyncbackoff and
asyncretry to make your asyncio code more robust and
easier to maintain. In this documentation, we’ll take a closer look at what
aiomisc
has to offer and how it can help you streamline your asyncio
service development.
Installation#
Installation is possible in standard ways, such as PyPI or installation from a git repository directly.
Installing from PyPI:
pip3 install aiomisc
Installing from github.com:
# Using git tool
pip3 install git+https://github.com/aiokitchen/aiomisc.git
# Alternative way using http
pip3 install \
https://github.com/aiokitchen/aiomisc/archive/refs/heads/master.zip
The package contains several extras and you can install additional dependencies if you specify them in this way.
With uvloop:
pip3 install "aiomisc[uvloop]"
With aiohttp:
pip3 install "aiomisc[aiohttp]"
Complete table of extras bellow:
example |
description |
---|---|
|
For running aiohttp applications. |
|
For running ASGI applications |
|
|
|
use croniter for scheduling tasks |
|
|
|
You might using rich for logging |
|
|
|
use uvloop as a default event loop |
You can combine extras values by separating them with commas, for example:
pip3 install "aiomisc[aiohttp,cron,rich,uvloop]"
Quick Start#
This section will cover how this library creates and uses the event loop and creates services. For more details see Tutorial section, and you can always refer to the Modules and API Reference sections for help.
Event-loop and entrypoint#
Let’s look at this simple example first:
import asyncio
import logging
import aiomisc
log = logging.getLogger(__name__)
async def main():
log.info('Starting')
await asyncio.sleep(3)
log.info('Exiting')
if __name__ == '__main__':
with aiomisc.entrypoint(log_level="info", log_format="color") as loop:
loop.run_until_complete(main())
This code declares an asynchronous main()
function that exits for
3 seconds. It would seem nothing interesting, but the whole point is in
the entrypoint
.
At the first glance the entrypoint
did not do much, just creates an
event-loop and transfers control to the user. However, under the hood, the
logger is configured in a separate thread, a pool of threads is created,
services are started, but more on that later as there are no services
in this example.
Alternatively, you can choose not to use an entrypoint
, just create an
event-loop and set it as a default for current thread:
import asyncio
import aiomisc
# * Installs uvloop event loop is it's has been installed.
# * Creates and set `aiomisc.thread_pool.ThreadPoolExecutor`
# as a default executor
# * Sets just created event-loop as a current event-loop for this thread.
aiomisc.new_event_loop()
async def main():
await asyncio.sleep(1)
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
The example above is useful if your code is already using an implicitly created
event loop, you will have to modify less code, just add
aiomisc.new_event_loop()
and all calls to asyncio.get_event_loop()
will return the created instance.
However, you can do with one call. Following example closes implicitly created asyncio event loop and install a new one:
import asyncio
import aiomisc
async def main():
await asyncio.sleep(3)
if __name__ == '__main__':
loop = aiomisc.new_event_loop()
loop.run_until_complete(main())
Services#
The main thing that an entrypoint
does is start and gracefully
stop services.
The service concept within this library means a class derived from
the aiosmic.Service
class and implementing the
async def start(self) -> None:
method and optionally the
async def stop(self, exc: Optional[ Exception]) -> None
method.
The concept of stopping a service is not necessarily is pressing Ctrl+C
keys by user, it’s actually just exiting the entrypoint
context manager.
The example below shows what your service might look like:
from aiomisc import entrypoint, Service
class MyService(Service):
async def start(self):
do_something_when_start()
async def stop(self, exc):
do_graceful_shutdown()
with entrypoint(MyService()) as loop:
loop.run_forever()
The entry point can start as many instances of the service as it likes, and all of them will start concurrently.
There is also a way if the start
method is a payload for a service,
and then there is no need to implement the stop method, since the running
task with the start
function will be canceled at the stop stage.
But in this case, you will have to notify the entrypoint
that the
initialization of the service instance is complete and it can continue.
Like this:
import asyncio
from threading import Event
from aiomisc import entrypoint, Service
event = Event()
class MyService(Service):
async def start(self):
# Send signal to entrypoint for continue running
self.start_event.set()
await asyncio.sleep(3600)
with entrypoint(MyService()) as loop:
assert event.is_set()
Note
The entrypoint
passes control to the body of the context manager only
after all service instances have started. As mentioned above, a start is
considered to be the completion of the start
method or the setting of
an start event with self.start_event.set()
.
The whole power of this library is in the set of already implemented or abstract services. Such as: AIOHTTPService, ASGIService, TCPServer, UDPServer, TCPClient, PeriodicService, CronService and so on.
Unfortunately in this section it is not possible to pay more attention to this, please pay attention to the Tutorial section section, there are more examples and explanations, and of cource you always can find out an answer on the API Reference or in the source code. The authors have tried to make the source code as clear and simple as possible, so feel free to explore it.
Versioning#
This software follows Semantic Versioning
Summary: it’s given a version number MAJOR.MINOR.PATCH, increment the:
MAJOR version when you make incompatible API changes
MINOR version when you add functionality in a backwards compatible manner
PATCH version when you make backwards compatible bug fixes
Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format.
In this case, the package version is assigned automatically with poem-plugins, it using on the tag in the repository as a major and minor and the counter, which takes the number of commits between tag to the head of branch.
How to develop?#
This project, like most open source projects, is developed by enthusiasts, you can join the development, submit issues, or send your merge requests.
In order to start developing in this repository, you need to do the following things.
Should be installed:
Python 3.7+ as
python3
Installed Poetry as
poetry
For setting up developer environment just execute:
# installing all dependencies poetry install # setting up pre-commit hooks poetry run pre-commit install # adding poem-plugins to the poetry poetry self add poem-plugins
- 1. Tutorial
- 2. Modules
- 2.1. entrypoint
- 2.2.
run()
shortcut - 2.3. Logging configuration
- 2.4. Services
- 2.4.1.
TCPServer
- 2.4.2.
UDPServer
- 2.4.3.
TLSServer
- 2.4.4.
TCPClient
- 2.4.5.
TLSClient
- 2.4.6.
RobustTCPClient
- 2.4.7.
RobustTLSClient
- 2.4.8.
PeriodicService
- 2.4.9. DNS Server
- 2.4.10.
CronService
- 2.4.11. Multiple services
- 2.4.12. Configuration
- 2.4.13. aiohttp service
- 2.4.14. asgi service
- 2.4.15. uvicorn service
- 2.4.16. GRPC service
- 2.4.17. Memory Tracer
- 2.4.18. Profiler
- 2.4.19. Raven service
- 2.4.20.
SDWatchdogService
- 2.4.21.
ProcessService
- 2.4.22.
RespawningProcessService
- 2.4.1.
- 2.5. Abstract connection pool
- 2.6. Context
- 2.7.
@aiomisc.timeout
- 2.8.
@aiomisc.asyncbackoff
- 2.9.
asyncretry
- 2.10. Circuit Breaker
- 2.11. cutout
- 2.12.
@aiomisc.aggregate
- 2.13. asynchronous file operations
- 2.14. Working with threads
- 2.15.
ProcessPoolExecutor
- 2.16. Utilities
- 2.17.
WorkerPool
- 2.18. Logging configuration
- 2.19. Pytest plugin
- 2.20.
Signal
- 2.21. Plugins
- 2.22. Statistic counters
- API Reference
- 1.
aiomisc
module- 1.1.
aiomisc.aggregate
module - 1.2.
aiomisc.backoff
module - 1.3.
aiomisc.circuit_breaker
module - 1.4.
aiomisc.compat
module - 1.5.
aiomisc.context
module - 1.6.
aiomisc.counters
module - 1.7.
aiomisc.cron
module - 1.8.
aiomisc.entrypoint
module - 1.9.
aiomisc.io
module - 1.10.
aiomisc.iterator_wrapper
module - 1.11.
aiomisc.log
module - 1.12.
aiomisc.periodic
module - 1.13.
aiomisc.plugins
module - 1.14.
aiomisc.pool
module - 1.15.
aiomisc.process_pool
module - 1.16.
aiomisc.recurring
module - 1.17.
aiomisc.signal
module - 1.18.
aiomisc.thread_pool
module - 1.19.
aiomisc.timeout
module - 1.20.
aiomisc.utils
module - 1.21.
aiomisc.worker_pool
module
- 1.1.
- 2.
aiomisc_log
module - 3.
aiomisc_worker
module
- 1.