Mongoengine: Calling connect with same alias will not recreate the connection.

Created on 3 Feb 2014  路  4Comments  路  Source: MongoEngine/mongoengine

The connect function will not re-create a connection of the same alias if it already exists. This prevents you from creating a new 'default' connection (or other alias) with different connection values (ie, different host, db, etc).
IMO this breaks 'the principle of least surprise' as this is acting more as a connection caching function than an actual connect function.

def connect(db, alias=DEFAULT_CONNECTION_NAME, **kwargs):
    """Connect to the database specified by the 'db' argument.

    Connection settings may be provided here as well if the database is not
    running on the default port on localhost. If authentication is needed,
    provide username and password arguments as well.

    Multiple databases are supported by using aliases.  Provide a separate
    `alias` to connect to a different instance of :program:`mongod`.

    .. versionchanged:: 0.6 - added multiple database support.
    """
    global _connections
    if alias not in _connections:
        register_connection(alias, db, **kwargs)

    return get_connection(alias)

To get the expected behavior, one must call disconnect first.
And it MUST be the global disconnect function, not the connection.disconnect(), as it won't be removed from the global connection list.

def disconnect(alias=DEFAULT_CONNECTION_NAME):
    global _connections
    global _dbs

    if alias in _connections:
        get_connection(alias=alias).disconnect()
        del _connections[alias]
    if alias in _dbs:
        del _dbs[alias]

Atleast that seems to be what you _should_ do.
The problem is, the models cache the connection themselves! If the connection changes, it isn't reflected in the models!

    @classmethod
    def _get_collection(cls):
        """Returns the collection for the document."""
        if not hasattr(cls, '_collection') or cls._collection is None:
            db = cls._get_db()
<snip>

However, the disconnect function isn't exposed publically, as it isn't included in the __all__ list in connection.py.

__all__ = ['ConnectionError', 'connect', 'register_connection',
           'DEFAULT_CONNECTION_NAME']

The disconnect function is also not mentioned in the documentation, which means the user must delve into the code to discover this (http://docs.mongoengine.org/en/latest/apireference.html).

The tutorials do not cover changing connections, only different connections per model.

Changing the existing logic could break applications using the connect function as a connection cache.

I believe at the least, the documentation should be updated to:

  1. Add the disconnect function and disambiguate between the disconnect function and connection.disconnect member.
  2. Cover changing connections in the tutorial.
  3. Update the connect function documentation to mention the disconnect function, connection.disconnect and the connection caching logic.

The code should be updated to:

  1. publicly expose the disconnect function via the __all__ list.
  2. Stop model's connection caching from breaking connect/disconnect.
  3. Re-create the connection if connect is called with different arguments.

See #566

ClienConnect

Most helpful comment

FFS! why is this still not fixed!?!?! Took me hours to figure this out...

Since I work with replicasets (which is a bitch all on its own) I connect, check the hosts en reconnect

The entire connect function is lacking a lot... the db parameter is only used to register within the connection but not for returning the connection. This means changing the database may not affect the alias. Secondly this also means I can't easily close a connection and reconnect via this function since it has no option to overwrite the existing connecting.

I would suggest getting rid of the alias as a key for the caching but using the connection parameters or host/db.

~~~python
def connect(db=None, alias=DEFAULT_CONNECTION_NAME, **kwargs):
"""Connect to the database specified by the 'db' argument.

Connection settings may be provided here as well if the database is not
running on the default port on localhost. If authentication is needed,
provide username and password arguments as well.

Multiple databases are supported by using aliases. Provide a separate
`alias` to connect to a different instance of :program:`mongod`.

See the docstring for `register_connection` for more details about all
supported kwargs.

.. versionchanged:: 0.6 - added multiple database support.
"""
if alias not in _connections:
    register_connection(alias, db, **kwargs)

return get_connection(alias)

~~~

All 4 comments

I'm now facing the same issue. I think the problem really boils down to the function disconnect() not removing stuff from global _connection_settings

When the connection.get_db() gets called it goes to really create a new connection, but loads the old settings of the previous connection at line https://github.com/MongoEngine/mongoengine/blob/45cb99125454c1ca15d8c40912e8f359353280cc/mongoengine/connection.py#L146

So disconnect could work if a same sort of del _connection_settings[alias] would be added

I agree with the problem described here and more generally, I think the whole Client/connect needs a full serious rewrite. It is seriously a piece of #$%! with these old-school globals

FFS! why is this still not fixed!?!?! Took me hours to figure this out...

Since I work with replicasets (which is a bitch all on its own) I connect, check the hosts en reconnect

The entire connect function is lacking a lot... the db parameter is only used to register within the connection but not for returning the connection. This means changing the database may not affect the alias. Secondly this also means I can't easily close a connection and reconnect via this function since it has no option to overwrite the existing connecting.

I would suggest getting rid of the alias as a key for the caching but using the connection parameters or host/db.

~~~python
def connect(db=None, alias=DEFAULT_CONNECTION_NAME, **kwargs):
"""Connect to the database specified by the 'db' argument.

Connection settings may be provided here as well if the database is not
running on the default port on localhost. If authentication is needed,
provide username and password arguments as well.

Multiple databases are supported by using aliases. Provide a separate
`alias` to connect to a different instance of :program:`mongod`.

See the docstring for `register_connection` for more details about all
supported kwargs.

.. versionchanged:: 0.6 - added multiple database support.
"""
if alias not in _connections:
    register_connection(alias, db, **kwargs)

return get_connection(alias)

~~~

I'm currently working on this. I don't plan to get rid of the alias immediately but I'll improve the connect method and fixing the disconnect method so that it will be usable

Was this page helpful?
0 / 5 - 0 ratings