#36439: Auth hashing blocks event loop if using asyncio
-------------------------------------+-------------------------------------
Reporter: robertaistleitner | Type:
| Cleanup/optimization
Status: new | Component:
| contrib.auth
Version: 5.1 | Severity: Normal
Keywords: async, auth, | Triage Stage:
asyncio, performance | Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
To a large extent, issues with auth in async auth has been fixed in
https://github.com/django/django/commit/50f89ae850f6b4e35819fe725a08c7e579bfd099,
I guess this is the last part of proper async implementation of
authentication.
There exist custom implementations for asyncio regarding checking a
password using the configured hashers which can be found in
https://github.com/django/django/blob/68c9f7e0b79168007e6ba0139fd315d7c44ca8c9/django/contrib/auth/hashers.py#L86-L91.
This implementation has a flaw because the CPU heavy calculation of the
hash is blocking the event loop of asyncio, causing the whole server to
stall and queueing up all the following authentications that may rush in
in case of heavy load.
My proposal is to use a ThreadPoolExecutor here to be able to unload the
work from the event loop:
{{{
CHECK_PASSWORD_THREAD_POOL_EXECUTOR = ThreadPoolExecutor(16)
async def acheck_password(password, encoded, setter=None,
preferred="default"):
"""See check_password()."""
# verify_password is cpu heavy and needs to be executed in a separate
thread to not block a running asyncio event loop
is_correct, must_update = await sync_to_async(
verify_password, thread_sensitive=False,
executor=CHECK_PASSWORD_THREAD_POOL_EXECUTOR
)(password, encoded, preferred=preferred)
if setter and is_correct and must_update:
await setter(password)
return is_correct
}}}
The number of available thread could be exposed via setting, or skipped
altogether by using a new thread on each verify_password call. What are
your thoughts on this?
--
Ticket URL: <
https://code.djangoproject.com/ticket/36439>
Django <
https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.