ldap3
ldap3 copied to clipboard
Add a version of the Connection class that better integrates with Asyncio
Maybe AsyncioConnection or something of that nomenclature
This has to be added in version 3 of the library because Asyncio isn't compatible with python 2, so python 2 support must be dropped first.
A lot of python processes have been moving towards usage of asyncio, rather than manually managing threads, since asyncio became part of core python. It would be nice if the ldap3 library had a version of Connection that provides "async def" style definitions of the various search/add/modify/etc. functions
Currently, any search/add/etc. functions on a connection object that isn't using the async connection strategy will block the main event loop for asyncio while waiting on a reply from the server.
The asyncio-friendly behavior that I'd want to support can be achieved with the current Connection object by using an async connection strategy any then putting every search/add/etc. operation into the following type of loop:
msg_id = conn.search(.....)
response = None
while response is None:
try:
response, result = conn.get_response(msg_id, timeout=0.001). # python doesn't have great sub-millisecond precision so use a 1 ms timeout to only wait if it's already coming in
except LDAPResponseTimeoutError:
# let other workers have a turn on the event loop while we wait on our response to come in
yield from asyncio.sleep(0)
but it would be good to natively support doing something like
conn = AsyncioConnection(....)
response, result = yield from conn.search(...)
to simplify usage of asyncio with ldap3 while also allowing callers to take advantage of all of the connection strategies to make programming with ldap3 in an asyncio environment easier
Have you recently worked on this? Also is there any schedule for v3 in general? This is definitely a feature we would like to use as most of our applications now also use asyncio
@septatrix I haven’t done much here, and I’m not sure that there’s a fixed schedule for v3 - the ideal is that v3 has any and all breaking changes that are desired so there’s a lot that needs to be looked at for it.
in the meanwhile there’s actually a way to make things a bit more asyncio friendly. If you use the ASYNC client strategy, you can combine if responses are in with asyncio.sleep(0) calls to make it sort of work
Maybe @cannatag could add this issue to the v3 milestone?
Also do you happen to know if the ASYNC mode is compatible with gevent (or eventlet, greenlet)?
Would this work with a conditional import? Keep all asyncio references confined to certain files and only import those under eligible versions of Python 3?
honestly it's kind of iffy. I might not be up to date on the latest in 3.9/10, but my understanding is that you can't simultaneously have a function be asyncio friendly and not asyncio friendly.
the async def
or @asyncio.coroute
pieces couldn't be conditional - you'd need an entirely new version of the Connection
object to support asyncio (thus the title of this issue). and there's also a lot of aspects of connections that aren't within the control of ldap3
- for example kerberos negotiation uses gssapi
and winkerberos
, which are both not asyncio-friendly afaik. so we might want an option to pass in a threadpool to use for pushing such operations off of the main thread.
so it's tough to implement and actually is more work then it seems like initially, with a lot of design choices to be made
It might be worth it to take a look how other projects like psycopg3 and sqlalchemy do this without too much code duplication
Also the ASYNC
strategy still has some blocking areas. E.g. the initial transmission for a search request still calls socket.send