Async boto3 client generator.
Project description
aboto3
WARNING - This project is archived and was only a test. Please use fully async clients like aioboto3
!
aboto3
is an async boto3 client generator!
There are other boto3-like libraries that offer asyncio but the interface can be quite different from normal boto3
clients.
The goal of aboto3
is to closely replicate the boto3
client interface with acceptable performance from the python ThreadPoolExecutor
!
API NOTE -
aboto3
was created with boto3 API compatibility in mind. Because of this it does not supportboto3
"Resources", and there is no plan to support them. New "Resources" are no longer being added toboto3
.
Performance NOTE - Because
aboto3
provides an async wrapper aroundboto3
, it is not truly async to it's core. It sends a boto3 call to a thread and the thread runs asynchronously.asyncio
tasks are much lighter weight than threads so if you want to run hundreds of concurrent calls with the best performance, pure async boto3 equivalents are a better fit.
Tutorial
To create an async client simply pass in the normal boto3
client to create an AIOClient
.
Use the async client, in a coroutine, like you would if the boto3 client's API calls were all async! See boto3
docs for details.
import asyncio
import aboto3
import boto3
# create a normal boto3 client
ec2_client = boto3.client("ec2")
# create the asyncio version from the client
aio_ec2_client = aboto3.AIOClient(ec2_client)
# you can still use the other client as usual
instances = ec2_client.describe_instances()
# the async client must be used in a coroutine
# but acts exactly the same as the boto3 client except method calls are async
async def aio_tester():
aio_instances = await aio_ec2_client.describe_instances()
return aio_instances
aio_instances = asyncio.run(aio_tester())
Pass in parameters to the coroutine like a normal client.
import asyncio
import aboto3
import boto3
ec2_client = boto3.client("ec2")
aio_ec2_client = aboto3.AIOClient(ec2_client)
instances = ec2_client.describe_instances(InstanceIds=["i-123412341234"])
async def aio_tester():
aio_instances = await aio_ec2_client.describe_instances(InstanceIds=["i-123412341234"])
return aio_instances
aio_instances = asyncio.run(aio_tester())
Get an async paginator from the aboto3
client.
import asyncio
import aboto3
import boto3
ec2_client = boto3.client("ec2")
aio_ec2_client = aboto3.AIOClient(ec2_client)
filters = [
{
"Name": "instance-type",
"Values": [
"t2.micro"
]
}
]
pages = []
pager = ec2_client.get_paginator("describe_instances")
for page in pager.paginate(Filters=filters):
pages.append(page)
# note the use of an "async for" loop so calls for a page are non-blocking.
async def aio_tester():
aio_pages = []
aio_pager = aio_ec2_client.get_paginator("describe_instances")
async for page in aio_pager.paginate(Filters=filters):
aio_pages.append(page)
return aio_pages
aio_pages = asyncio.run(aio_tester())
Client exceptions can be caught on the AIOClient
just like a normal boto3
client.
botocore
exceptions are caught as normal.
import asyncio
import aboto3
import boto3
ssm_client = boto3.client("ssm")
aio_ssm_client = aboto3.AIOClient(ssm_client)
try:
ssm_client.get_parameter(Name="/unknown/param")
except ssm_client.exceptions.ParameterNotFound as error:
print("found an error here: {}".format(error))
async def aio_tester():
try:
aio_ssm_client.get_parameter(Name="/unknown/param")
except aio_ssm_client.exceptions.ParameterNotFound as error:
print("found an error here: {}".format(error))
aio_pages = asyncio.run(aio_tester())
You can also use boto3
augmenting libraries since aboto3
is only a wrapper.
Optimization
When an AIOClient
is created it will automatically create a ThreadPoolExecutor
to run the boto3 calls asynchronously. The size of max workers of the pool is determined by the boto3 client's config for max_pool_connections
. By default this is 10.
See botocore Config Reference for more details.
The thread pool adds a small amount of overhead for each AIOClient
that is created (though this is far less than the overhead of creating a boto3 client). To save some initialization time or have more control over total number of threads you can provide your own ThreadPoolExecutor
and share this between clients.
import asyncio
from concurrent.futures import ThreadPoolExecutor
import aboto3
import boto3
boto3_thread_pool = ThreadPoolExecutor(max_workers=16)
ec2_client = boto3.client("ec2")
aio_ec2_client = AIOClient(
boto3_client=ec2_client,
thread_pool_executor=boto3_thread_pool
)
rds_client = boto3.client("rds")
aio_rds_client = AIOClient(
boto3_client=rds_client,
thread_pool_executor=boto3_thread_pool
)
In general, for applications, you will want to cache the clients if possible. Try not to create a new one in every function. For applications, a shared thread pool can be useful in limiting the total number of threads, when necessary.
If you are making large numbers of concurrent calls with the same AIOClient
you may want to pass in a custom botocore.config.Config
to the boto3 client with a higher max_pool_connections
. If you are using a shared thread pool you may also need to increase the max workers in that as well.
The example below will allow up to 32 concurrent calls to be in flight for the EC2 and RDS AIOClient
's.
import asyncio
from concurrent.futures import ThreadPoolExecutor
import aboto3
import boto3
from botocore.config import Config
boto_config = Config(
max_pool_connections=32
)
boto3_thread_pool = ThreadPoolExecutor(max_workers=64)
ec2_client = boto3.client("ec2", config=boto_config)
aio_ec2_client = AIOClient(
boto3_client=ec2_client,
thread_pool_executor=boto3_thread_pool
)
rds_client = boto3.client("rds", config=boto_config)
aio_rds_client = AIOClient(
boto3_client=rds_client,
thread_pool_executor=boto3_thread_pool
)
Or if you don't care about sharing the thread pool just pass in the config
and each AIOClient
will have it's own pool of 32 threads.
import asyncio
import aboto3
import boto3
from botocore.config import Config
boto_config = Config(
max_pool_connections=32
)
ec2_client = boto3.client("ec2", config=boto_config)
aio_ec2_client = AIOClient(boto3_client=ec2_client)
rds_client = boto3.client("rds", config=boto_config)
aio_rds_client = AIOClient(boto3_client=rds_client)
Development
Install the package in editable mode with dev dependencies.
(venv) $ pip install -e .[dev]
nox
is used to manage various dev functions.
Start with
(venv) $ nox --help
pyenv
is used to manage python versions.
To run the nox tests for applicable python version you will first need to install them.
In the root project dir run:
(venv) $ pyenv install
Changelog
Changelog for aboto3
.
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[0.1.1] - 2024-01-28
Added
Tests for python 3.12
Changed
Updated README to reflect recommendations.
Removed
Support for python 3.7
[0.1.0] - 2023-06-22
Initial Release.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file aboto3-0.1.2.tar.gz
.
File metadata
- Download URL: aboto3-0.1.2.tar.gz
- Upload date:
- Size: 6.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/5.1.0 CPython/3.8.18
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 5222ddeb562a6238ebaf0e490ff38954c4309509810d70dc199d0c8f0accda52 |
|
MD5 | a65e91d6cdf3dea81a7a8fc3f952c0a2 |
|
BLAKE2b-256 | 3005a31f99f1776c4f4d7dc987e1305af7b4eb22c8fb7e31999c19917a07bcbd |
File details
Details for the file aboto3-0.1.2-py3-none-any.whl
.
File metadata
- Download URL: aboto3-0.1.2-py3-none-any.whl
- Upload date:
- Size: 6.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/5.1.0 CPython/3.8.18
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 612d6d025da7bf6cdb002b49ad9282602717348b0ed526fe70cca203ec362a4b |
|
MD5 | 2559825e05befc05f8ef052146517b40 |
|
BLAKE2b-256 | d27ae5eb3f09e604b5ca34d69d959d37d77504491a25f77eb5232fe350755ec9 |