Markus
Markus

Reputation: 370

PyMongo connections not being released: Error as no more connections to MongoDB available

I have a script which uses up all available connections of the locally running MongoDB and then exists with this error message:

pymongo.errors.AutoReconnect: [Errno 4] Interrupted system call

The error message in /var/log/mongodb/mongod.log is:

[initandlisten] connection refused because too many open connections: 819

The Mongo-Shell gives this output when the script is being invoked:

> db.serverStatus().connections
{ "current" : 1, "available" : 818 }  // Script not yet started
> db.serverStatus().connections
{ "current" : 400, "available" : 419 }  // Losing connections
> db.serverStatus().connections
{ "current" : 638, "available" : 181 }
> db.serverStatus().connections
{ "current" : 804, "available" : 15 }
> db.serverStatus().connections
{ "current" : 819, "available" : 0 }  // Script terminates
> db.serverStatus().connections
{ "current" : 1, "available" : 818 }  // Script terminated

I am not able to post the original script, but the following "sanitized" snippet hopefully gives an idea. Basically, I am running all sorts of different queries and updates across several collections.

Most importantly only 5 of 11 database statements will sometimes not release their connection. The other 6 statements will always leave as many free connections as there were before the statement.

mc = pymongo.Connection()
db = mc.database

def available():
    """ Return the number of available connections """
    return db.command("serverStatus")['connections']['available']

def process():
    while True:
        # ...
        # Connections lost:
        conns = available()
        coll_a = db.coll_a.find_and_modify(
                query={'x': x},
                update={'$pop': {'x': -1}},
                fields={'x': 1})
        if conns > available():
            print('Fewer connections')
        # ...
        # No connections lost:
        db.coll_a.update({'x': x}, {'$pullAll': {'x': [x]}})
        # ...
        # No connections lost:
        coll_d = db.coll_d.find_and_modify(
                query={'x': x,},
                update={'$set': {'x': x}},
                fields={'x': 1})
        # ...
        # No connections lost:
        coll_b_cursor = db.coll_b.find({'x': x}, {'x': 1})
        # ...
        # No connections lost:
        coll_e_cursor = db.coll_e.find({'$or': [{'x': x}, {'x': x}]})
        # ...
        for item in coll_e_cursor:
            # No connections lost:
            coll_b = db.coll_b.find({'x': x}).count()
        # ...
        # No connections lost:
        coll_b_cursor = db.coll_b.find({'x': x}, {'x': x})
        # ...
        for x in y:
            if x:
                # Connections lost:
                conns = available()
                db.coll_b.update({'x': x}, {'$unset': {'x': 1}})
                if conns > available():
                    print('Fewer connections')
            # ...
            # Connections lost:
            conns = available()
            coll_b = db.coll_b.find_and_modify(
                    query={'x': x},
                    update={'$set': {'x': x}},
                    fields={'x': 1},
                    upsert=True)
            if conns > available():
                print('Fewer connections')
            # ...
            # Connections lost:
            conns = available()
            coll_c_1 = db.coll_c.find_one({'x': x})
            coll_c_2 = db.coll_c.find_one({'x': x})
            if conns > available():
                print('Fewer connections')
        # ...
        # Connections lost:
        conns = available()
        db.coll_b.update({'x': x}, {'$unset': {'x': 1}})
        if conns > available():
            print('Fewer connections')

PyMongo: 2.2.1

MongoDB: 2.0.6

Upvotes: 0

Views: 1065

Answers (1)

Markus
Markus

Reputation: 370

The connections were not lost where it seemed but when.

I overlooked a thread was started somewhere in process():

threading.Thread(target=target, args=(args)).start()

This thread made a database call.

The while loop in process() was fast enough so that many threads were running simultaneously. Using up all available database connections.

Without launching these threads, the number of available database connections remains constant.

Upvotes: 1

Related Questions