<div dir="ltr">I am under ubuntu, python2.7, I have installed python-ldap few mounths ago ..<br>Here is my code:<br><br>#!/usr/bin/python<br><br># Import the python-ldap modules<br>import ldap,ldapurl<br># Import specific classes from python-ldap<br>from ldap.ldapobject import ReconnectLDAPObject<br>from ldap.syncrepl import SyncreplConsumer<br><br># Import modules from Python standard lib<br>import shelve,signal,time,sys,logging<br>import eventlet<br>import thread<br><br># Global state<br>watcher_running = True<br>ldap_connection = False<br><br><br><br>class SyncReplConsumer(ReconnectLDAPObject,SyncreplConsumer):<br>    """<br>    Syncrepl Consumer interface<br>    """<br>    def __init__(self,db_path,*args,**kwargs):<br>        # Initialise the LDAP Connection first<br>        ldap.ldapobject.ReconnectLDAPObject.__init__(self, *args, **kwargs)<br>        # Now prepare the data store<br>        self.__data = shelve.open(db_path, 'c')<br>        # We need this for later internal use<br>        self.__presentUUIDs = dict()<br><br>    def __del__(self):<br>            # Close the data store properly to avoid corruption<br>            self.__data.close()<br><br>    def syncrepl_get_cookie(self):<br>        if 'cookie' in self.__data:<br>            return self.__data['cookie']<br><br>    def syncrepl_set_cookie(self,cookie):<br>        self.__data['cookie'] = cookie<br><br>    def syncrepl_entry(self,dn,attributes,uuid):<br>        global result<br>        # First we determine the type of change we have here (and store away the previous data for later if needed)<br>        previous_attributes = dict()<br>        if uuid in self.__data:<br>            change_type = 'modify'<br>            previous_attributes = self.__data[uuid]<br>        else:<br>            change_type = 'add'<br>        # Now we store our knowledge of the existence of this entry (including the DN as an attribute for convenience)<br>        attributes['dn'] = dn<br>        self.__data[uuid] = attributes<br>        # Debugging<br>        print 'Detected', change_type, 'of entry:', dn<br>        # If we have a cookie then this is not our first time being run, so it must be a change<br>        if 'ldap_cookie' in self.__data:<br>                self.perform_application_sync(dn, attributes, previous_attributes)<br><br>    def syncrepl_delete(self,uuids):<br>        global result<br>        # Make sure we know about the UUID being deleted, just in case...<br>        uuids = [uuid for uuid in uuids if uuid in self.__data]<br>        # Delete all the UUID values we know of<br>        for uuid in uuids:<br>            print 'Detected deletion of entry:', self.__data[uuid]['dn']<br>            del self.__data[uuid]<br><br>    def syncrepl_present(self,uuids,refreshDeletes=False):<br>        # If we have not been given any UUID values, then we have recieved all the present controls...<br>        if uuids is None:<br>            # We only do things if refreshDeletes is false as the syncrepl extension will call syncrepl_delete instead when it detects a delete notice<br>            if refreshDeletes is False:<br>                deletedEntries = [uuid for uuid in self.__data.keys() if uuid not in self.__presentUUIDs and uuid != 'ldap_cookie']<br>                self.syncrepl_delete( deletedEntries )<br>            # Phase is now completed, reset the list<br>            self.__presentUUIDs = {}<br>        else:<br>            # Note down all the UUIDs we have been sent<br>            for uuid in uuids:<br>                    self.__presentUUIDs[uuid] = True<br><br>    def perform_application_sync(self,dn,attributes,previous_attributes):<br>        print 'Performing application sync for:', dn<br>        return True<br><br><br># Shutdown handler<br>#def commenceShutdown(signum, stack):<br>def commenceShutdown():<br>    # Declare the needed global variables<br>    global watcher_running, ldap_connection<br>    print 'Shutting down!'<br><br>    # We are no longer running<br>    watcher_running = False<br><br>    # Tear down the server connection<br>    if( ldap_connection ):<br>            del ldap_connection<br><br>    # Shutdown<br>    sys.exit(0)<br><br>def mainOfSyncrepl(threadName):<br>    # Time to actually begin execution<br>    # Install our signal handlers<br>#    signal.signal(signal.SIGTERM,commenceShutdown)<br>#    signal.signal(signal.SIGINT,commenceShutdown)<br>    try:<br>      ldap_url = ldapurl.LDAPUrl('ldap://Address/dc=test,dc=com?*?sub?(objectClass=*)?bindname=cn=admin%2cdc=test%2cdc=com,X-BINDPW=password')#ldapurl.LDAPUrl(sys.argv[1])<br>    #  ldap_url = ldapurl.LDAPUrl(link)<br>      database_path = '<a href="http://example.com">example.com</a>'#sys.argv[2]<br>    #  database_path = pathName<br>    except IndexError,e:<br>      print 'Usage: syncrepl-client.py <LDAP URL> <pathname of database>'<br>      sys.exit(1)<br>    except ValueError,e:<br>      print 'Error parsing command-line arguments:',str(e)<br>      sys.exit(1)<br><br>    while watcher_running:<br>        print 'Connecting to LDAP server now...'<br>        # Prepare the LDAP server connection (triggers the connection as well)<br>        ldap_connection = SyncReplConsumer(database_path,ldap_url.initializeUrl())<br><br>        # Now we login to the LDAP server<br>        try:<br>        ldap_connection.simple_bind_s(ldap_url.who,ldap_url.cred)<br>        except ldap.INVALID_CREDENTIALS, e:<br>        print 'Login to LDAP server failed: ', str(e)<br>        sys.exit(1)<br>        except ldap.SERVER_DOWN:<br>        continue<br><br>        # Commence the syncing<br>        print 'Commencing sync process'<br>        ldap_search = ldap_connection.syncrepl_search(<br>          ldap_url.dn or '',<br>          ldap_url.scope or ldap.SCOPE_SUBTREE,<br>          mode = 'refreshAndPersist',<br>          filterstr = ldap_url.filterstr or '(objectClass=*)'<br>        )<br>        print 'After syncrepl_search.'<br>        try:<br>        while ldap_connection.syncrepl_poll( all = 1, msgid = ldap_search):<br>            pass<br>        except KeyboardInterrupt:<br>        # User asked to exit<br>        commenceShutdown()<br>        pass<br>        except Exception, e:<br>        # Handle any exception<br>        if watcher_running:<br>            print 'Encountered a problem, going to retry. Error:', str(e)<br>            time.sleep(5)<br>        pass<br><br># Define a function for the 2nd thread<br>def print_time(ThreadName):<br>        count = 0<br>    delay = 3<br>        while 1:#count < 5:<br>            count += 1<br>            print "%s: %s" % (ThreadName, time.ctime(time.time()) )<br>            time.sleep(delay)<br><br><br><br>print 'Before call threads'<br><br>syncreplEvt1 = eventlet.spawn(mainOfSyncrepl, "Thread-1",)<br>syncreplEvt2 = eventlet.spawn(print_time, "Thread-2",)<br>#syncreplEvt3 = eventlet.spawn(print_time, "Thread-3",)<br><br>print 'After call threads'<br><br>syncreplEvt1.wait()<br>syncreplEvt2.wait()<br>#syncreplEvt3.wait()<br></div><div class="gmail_extra"><br><div class="gmail_quote">2016-01-08 7:56 GMT-08:00 Michael Ströder <span dir="ltr"><<a href="mailto:michael@stroeder.com" target="_blank">michael@stroeder.com</a>></span>:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">David Gabriel wrote:<br>
> After some investigation in the source code I think the function 'result4'<br>
> located in the file ldapobject.py is the responsible of this blocking<br>
> behaviour.<br>
<br>
</span>1. Please note that I personally do not feel responsible for the code *fork* on<br>
github.<br>
<br>
2. You did not tell us any other relevant details like<br>
- OS<br>
- Python version<br>
- python-ldap version (from where?)<br>
- whether python-ldap is linked against libldap_r etc.<br>
<br>
While method LDAPObject.result4() is called in a blocking manner it's IMHO<br>
likely not the cause for your code not being executed in parallel.<br>
<br>
Frankly I don't see any reason why it's not possible to run the blocking<br>
syncrepl client code in one thread and having other code running in separate<br>
threads.<br>
<br>
It might help if you would post a *small* code example with threads illustrating<br>
what you're trying to achieve and which shows your blocking issue.<br>
<br>
Ciao, Michael.<br>
<br>
</blockquote></div><br></div>