-
-
Notifications
You must be signed in to change notification settings - Fork 184
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix detected blocking call inside the event loop #1120
Conversation
sessions should be cached for the life of use so if this is a major issue the session should be kept around for a longer time. really botocore needs to speed this up on their end because it's way too slow |
Until then we have a fix anyway. |
I'm hesitant of doing this as |
It does looks like
|
Any feedback @thehesiod ? Thank you in advance |
so this seems like an issue with the aws component, why doesn't it do the session/client creation during |
like i was saying, it should cache the session/client there, or if you don't want to hold onto the client, perhaps just pre-warm up the botocore cache |
actually, this is invalid as botocore is not thread safe, with this you could have two requests, running in two different threads, trying to initialize the cache at the same time. closing |
@chemelli74 Thanks for trying to fix this. This problem must be solved eventually (unless the intent is WONTFIX). Please open an issue instead to track this in the long term. Thanks. |
ya let me know if I missed something, I truly believe this is a botocore issue. The fact they're reading a ton of JSON files is unsustainable. probably should be done on the fly per service when you use it...and even then should be in a post-processed state, like their build should generate python code based on those json files. |
so I looked a little into this, it seems like they use an |
What about pathlib ? |
that uses aiofiles which just uses a threadpool again: https://github.com/Tinche/aiofiles/tree/main/src/aiofiles |
i guess at the aiofiles level though it doesn't matter. But it sounds like there's a better solution |
If you point me towards the solution you prefer, I'll try to work on it. EDIT: Opened issue on |
Here the official answer from botocore repo: boto/botocore#3222 What can we do to progress then ? |
edit: sorry, this is basically what @thehesiod suggested #1120 (comment). I also think it's the obvious solution for that HomeAssistant specific issue. This might be a crazy idea, but if
then
This would be a fix over at HomeAssistant. What do you think? |
This doesn’t seem like a Home Assistant specific issue. Any asyncio application is going to have its event loop blocked. The only difference is that Home Assistant is aware of its loop being blocked where-as another application may not be able to detect it. |
botocore (or us?) could provide some sort of synchronuous helper function to pre-populate the cache. Home Assistant or anyone else could then choose to run it as part of their setup routine, e.g. via asyncio.to_thread() and no one else would be affected. Does that make sense? Btw, there are Python platforms that lack multithreading support. That's why I think @thehesiod has a point in not resorting to helper threads in this project unless absolutely necessary. |
this isn't an aiobotocore problem I don't think, but a botocore problem, or do you need to go through an async call to get to the cache warmup? secondly they can already do this themselves without the need for a helper |
Why you think so ? |
I suppose if we find a good async file API to use then it would be an async problem. but then that wouldn't require an init function. in terms of an init function that would equally apply to sync, however you'll then potentially run into locking issues |
@thehesiod how can we progress ? |
@chemelli74 suggest doing research of a good async API for aiobotocore to use. This will be a huge project though. Furthermore there are better ways to warm-up aiobotocore, if homeassistant wants to do that I already gave some suggestions like: #1120 (comment). They should init and keep the aioboto clients around instead of creating them on the fly |
this is really a solved issue, we due the same thing, like in aiohttp server using the |
There is another approach we could investigate:
@thehesiod: What is your opinion? @chemelli74: Does that make sense to you? |
Something like this sounds like a good solution. Maybe a flag to enable loading models in the executor. Rough untested proof of concept. diff --git a/aiobotocore/client.py b/aiobotocore/client.py
index 762ae52..4428e88 100644
--- a/aiobotocore/client.py
+++ b/aiobotocore/client.py
@@ -1,3 +1,4 @@
+import asyncio
from botocore.awsrequest import prepare_request_dict
from botocore.client import (
BaseClient,
@@ -40,26 +41,17 @@ class AioClientCreator(ClientCreator):
api_version=None,
client_config=None,
auth_token=None,
+ load_executor=False,
):
responses = await self._event_emitter.emit(
'choose-service-name', service_name=service_name
)
service_name = first_non_none_response(responses, default=service_name)
- service_model = self._load_service_model(service_name, api_version)
- try:
- endpoints_ruleset_data = self._load_service_endpoints_ruleset(
- service_name, api_version
- )
- partition_data = self._loader.load_data('partitions')
- except UnknownServiceError:
- endpoints_ruleset_data = None
- partition_data = None
- logger.info(
- 'No endpoints ruleset found for service %s, falling back to '
- 'legacy endpoint routing.',
- service_name,
- )
-
+ if load_executor:
+ model_data = await asyncio.get_running_loop().run_in_executor(None,self._load_models, service_name, api_version)
+ else:
+ model_data = self._load_models(service_name, api_version)
+ service_model, endpoints_ruleset_data, partition_data = model_data
cls = await self._create_client_class(service_name, service_model)
region_name, client_config = self._normalize_fips_region(
region_name, client_config
@@ -104,6 +96,23 @@ class AioClientCreator(ClientCreator):
)
return service_client
+ def _load_models(self, service_name, api_version):
+ service_model = self._load_service_model(service_name, api_version)
+ try:
+ endpoints_ruleset_data = self._load_service_endpoints_ruleset(
+ service_name, api_version
+ )
+ partition_data = self._loader.load_data('partitions')
+ except UnknownServiceError:
+ endpoints_ruleset_data = None
+ partition_data = None
+ logger.info(
+ 'No endpoints ruleset found for service %s, falling back to '
+ 'legacy endpoint routing.',
+ service_name,
+ )
+ return service_model, endpoints_ruleset_data, partition_data
+
async def _create_client_class(self, service_name, service_model):
class_attributes = self._create_methods(service_model)
py_name_to_operation_name = self._create_name_mapping(service_model) |
Description of Change
Fix detected blocking call inside the event loop. Reference HomeAssistant latest build:
Assumptions
none
Checklist for All Submissions
Checklist when updating botocore and/or aiohttp versions