Net::LDAP connection semantics problem and nested blocks.

L

Luke Daley

Hi,

I am working with the Net::LDAP library to communicate with active
directory. The connection semantics of that library are causing me
problems which I am trying to solve. The library was designed to
connect and then disconnect from the LDAP server before and after
each operation. I am running into a problem where the server is
refusing connections because of too many successive connections.

Some background....

I have a Net::LDAP subclass that among other things, supplies
credential and connection information to the parent on construction
based on a single key string that is given.

class MyLDAP < Net::LDAP

@cache = {}

def self.get(key)
if @cache.has_key? key
@cache[key]
else
@cache[key] = CortecsLDAP.new(key)
end
end

def initialize(key)
super self.connect_details_for_key(key)
end

def self.connect_details_for_key(key)
# Connect to DB and get details here relating to key
end

The caching business is because this it is common for 1000+ ldap
operations to happen in one execution so I thought I was being more
efficient in holding the connections open like that.

The semantics of Net::LDAP however open and close underling tcp
connection before and after each operation. Basically making my
caching obsolete. However, Net::LDAP provides the method open() at
the class and object level which takes a block and passes a Net::LDAP
object to the block, keeping its connection open for the duration of
the block. What I would like to do is be able to hold open all of the
objects in the cache for the duration of a block. This is probably
what I would want the interface to look like....

LDAPSession.open do | ldap_connection_cache |
my_ldap_instance = ldap_connection_cache.get('some_key')
my_other_ldap_instance = ldap_connection_cache.get('some_other_key')
end

The important thing here is that my_ldap_instance and
my_other_ldap_instance remain open for the whole time they are in the
block they are in. The only way to keep a Net::LDAP connection open
is to use the open() method described above and pass it a block.

I hope that makes sense to someone who can help.

Cheers.
 
L

Luke Daley

What LDAP operations are you performing here?

In the particular case when I hit the problem, it was an attribute
level modify operation. I realise my original post was extremely hard
to decipher, I was rather pressed for time when I put it together.

I have a script which consumes 'jobs' off a queue. One of the jobs
may be to update the name details for a particular user in domain a,
the next to update the phone number in domain b. Therefore opening
one connection using open() is not an option.

I have thought long and hard about this and I can't come up with a
solution. The only way for this to work the way I want would be to
have a flag that changes the connection model and maybe allows me to
specify when to open/close the underlying connection. However, I see
from the in code comments that it was an explicit design decision to
have the API work the way it does. I do understand the reason for
this, but it just doesn't suit my needs for this.

If this is something that you don't wish too change (quite
reasonable) I will go back to the other ruby ldap options.

On a side note, your ldap implementation performs very well compared
to the Perl net::ldap which I was surprised about. It may have been a
peculiarity of my environment, but when I moved to Perl to get the
task I needed done, there was a noticeable slow down in processing
large result sets compared to your ruby implementation.

Cheers.
 
F

Francis Cianfrocca

In the particular case when I hit the problem, it was an attribute
level modify operation. I realise my original post was extremely hard
to decipher, I was rather pressed for time when I put it together.

I have a script which consumes 'jobs' off a queue. One of the jobs
may be to update the name details for a particular user in domain a,
the next to update the phone number in domain b. Therefore opening
one connection using open() is not an option.


In regard to the design decision in the library: it's essential to be
able to document and depend on the network behavior of Net::LDAP.
That's more important than that it obey one semantics or another. The
decision came from years of experience with the various
Michigan-derived C implementations, which try to wrap the connection
away from the API, which in turn leads to bizarre, hard-to-find bugs.

Why don't you put your queue consumer inside the Net::LDAP#open block
and let it run as long as it wants to? You can put multiple #open
calls on different threads if you have to connect to more than one
LDAP server. The only thing I would be concerned about is that the
LDAP servers may time out your connections, but you can manage that by
putting your own timeout in your Queue-query.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,777
Messages
2,569,604
Members
45,214
Latest member
JFrancisDavis

Latest Threads

Top