From e39f746776e68fe409219061137d5428ee6aeb6c Mon Sep 17 00:00:00 2001 From: Anand Ganapathy Date: Fri, 13 Dec 2013 13:34:23 -0800 Subject: [PATCH 01/10] fixing the access to database to self.database otherwise this was creating a database called 'database' and syncdb was failing because of auth issues --- django_mongodb_engine/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/django_mongodb_engine/base.py b/django_mongodb_engine/base.py index 2b0aafb6..858815f3 100644 --- a/django_mongodb_engine/base.py +++ b/django_mongodb_engine/base.py @@ -188,7 +188,7 @@ def __init__(self, *args, **kwargs): def get_collection(self, name, **kwargs): if (kwargs.pop('existing', False) and - name not in self.connection.database.collection_names()): + name not in self.database.collection_names()): return None collection = self.collection_class(self.database, name, **kwargs) if settings.DEBUG: From 48bb9fdbcbfc08947d603f93e178a32d307959dc Mon Sep 17 00:00:00 2001 From: Anand Ganapathy Date: Sun, 15 Dec 2013 16:59:51 -0800 Subject: [PATCH 02/10] remove the logging error for now, will follow up on this --- django_mongodb_engine/__init__.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/django_mongodb_engine/__init__.py b/django_mongodb_engine/__init__.py index 381ab71e..8c9ea595 100644 --- a/django_mongodb_engine/__init__.py +++ b/django_mongodb_engine/__init__.py @@ -15,8 +15,8 @@ # setup.py imports this file in order to read version/author/... metadata # but does not necessarily have a Django context. import logging - logging.error('Error while trying to get django' - ' settings module.\nError was: {0}'.format(str(exc))) + #logging.error('Error while trying to get django' + # ' settings module.\nError was: {0}'.format(str(exc))) else: try: # It might be irritating that django-mongodb-engine registers itself as @@ -46,5 +46,5 @@ # setup.py imports this file in order to read version/author/... metadata # but does not necessarily have a Django context. import logging - logging.error('Error while trying to get django' - ' settings module.\nError was: {0}'.format(str(exc))) + #logging.error('Error while trying to get django' + # ' settings module.\nError was: {0}'.format(str(exc))) From a4ab28602c429887e8810e441966bef9110d628b Mon Sep 17 00:00:00 2001 From: Chaks Chigurupati Date: Tue, 6 May 2014 16:33:19 -0700 Subject: [PATCH 03/10] Refs#4708 Create a short index name for cases where auto-generated index name is too long --- django_mongodb_engine/creation.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/django_mongodb_engine/creation.py b/django_mongodb_engine/creation.py index 6ccd62d0..0dc3fe95 100644 --- a/django_mongodb_engine/creation.py +++ b/django_mongodb_engine/creation.py @@ -2,6 +2,10 @@ from pymongo import DESCENDING +from pymongo.errors import OperationFailure + +from random import randint + from djangotoolbox.db.creation import NonrelDatabaseCreation from .utils import make_index_list @@ -39,7 +43,14 @@ def ensure_index(*args, **kwargs): print "Installing indices for %s.%s model." % \ (meta.app_label, meta.object_name) ensure_index.first_index = False - return collection.ensure_index(*args, **kwargs) + try: + return collection.ensure_index(*args, **kwargs) + except OperationFailure, e: + # Try with a short name for the index in case the + # auto-generated index name is too long + index_name = meta.object_name + "_index_" + str(randint(1,100000)) + return collection.ensure_index(*args, name=index_name, **kwargs) + ensure_index.first_index = True newstyle_indexes = getattr(meta, 'indexes', None) From 1f8f7b7ca09dfddc5b48086a858a73186f010a12 Mon Sep 17 00:00:00 2001 From: Chaks Chigurupati Date: Tue, 6 May 2014 17:24:29 -0700 Subject: [PATCH 04/10] Refs#4708 printing an error message before retrying a shorter index name --- django_mongodb_engine/creation.py | 1 + 1 file changed, 1 insertion(+) diff --git a/django_mongodb_engine/creation.py b/django_mongodb_engine/creation.py index 0dc3fe95..bd0667f9 100644 --- a/django_mongodb_engine/creation.py +++ b/django_mongodb_engine/creation.py @@ -49,6 +49,7 @@ def ensure_index(*args, **kwargs): # Try with a short name for the index in case the # auto-generated index name is too long index_name = meta.object_name + "_index_" + str(randint(1,100000)) + print "Error installing index on %s: %s, trying shorter index name: %s" % (meta.object_name, str(e), index_name) return collection.ensure_index(*args, name=index_name, **kwargs) ensure_index.first_index = True From 19c1c9bfe5fbf7061fd9569d045fa7ed1c74a61a Mon Sep 17 00:00:00 2001 From: Anand Ganapathy Date: Fri, 27 Feb 2015 12:13:46 -0800 Subject: [PATCH 05/10] refs#16900 closing mongo connection on close --- django_mongodb_engine/base.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/django_mongodb_engine/base.py b/django_mongodb_engine/base.py index 858815f3..e8bbb973 100644 --- a/django_mongodb_engine/base.py +++ b/django_mongodb_engine/base.py @@ -254,4 +254,9 @@ def _rollback(self): pass def close(self): + if self.connected: + self.connection.close() + del self.connection + del self.database + self.connected = False pass From 62f3aa41c4755a1c84994a7f86fa4bfb1c1c72d7 Mon Sep 17 00:00:00 2001 From: Anand Ganapathy Date: Thu, 9 Apr 2015 15:16:54 -0700 Subject: [PATCH 06/10] refs#19069 handle auth failures properly; support connection retries --- django_mongodb_engine/base.py | 63 ++++++++++++++++++++++++++--------- 1 file changed, 48 insertions(+), 15 deletions(-) diff --git a/django_mongodb_engine/base.py b/django_mongodb_engine/base.py index e8bbb973..a090790c 100644 --- a/django_mongodb_engine/base.py +++ b/django_mongodb_engine/base.py @@ -2,6 +2,8 @@ import datetime import decimal import sys +import traceback +import time from django.conf import settings from django.core.exceptions import ImproperlyConfigured @@ -184,6 +186,12 @@ def __init__(self, *args, **kwargs): self.introspection = DatabaseIntrospection(self) self.validation = DatabaseValidation(self) self.connected = False + ''' this dictates if we want to close connection at the end of each request or cache it (old behavior) ''' + self.close_connection = kwargs.pop('close_connection', True) + ''' number of times to retry the connection on failure ''' + self.conn_retries = kwargs.pop('conn_retries', 10) + ''' time to sleep between retries ''' + self.conn_sleep_interval = kwargs.pop('conn_sleep_interval', 2) del self.connection def get_collection(self, name, **kwargs): @@ -226,19 +234,44 @@ def pop(name, default=None): for key in options.iterkeys(): options[key.lower()] = options.pop(key) - try: - self.connection = Connection(host=host, port=port, **options) - self.database = self.connection[db_name] - except TypeError: - exc_info = sys.exc_info() - raise ImproperlyConfigured, exc_info[1], exc_info[2] - - if user and password: - if not self.database.authenticate(user, password): - raise ImproperlyConfigured("Invalid username or password.") - - self.connected = True - connection_created.send(sender=self.__class__, connection=self) + attempts = 0 + while True: + try: + try: + self.connection = Connection(host=host, port=port, **options) + self.database = self.connection[db_name] + except TypeError: + exc_info = sys.exc_info() + raise ImproperlyConfigured, exc_info[1], exc_info[2] + + if user and password: + if not self.database.authenticate(user, password): + raise ImproperlyConfigured("Invalid username or password.") + + self.connected = True + connection_created.send(sender=self.__class__, connection=self) + break + except Exception as e: + print 'MongoConnectionFailure ', str(e) + print traceback.format_exc() + + ''' Make sure we set connected to False just in case we failed on the send ''' + self.connected = False + + ''' initialize these instance variables, so that we can delete them ''' + ''' this will ensure that the __get_attr__ class method properly reconnects ''' + self.database = None + self.connection = None + del self.database + del self.connection + + attempts += 1 + if attempts < self.conn_retries: + time.sleep(self.conn_sleep_interval) + print 'MongoConnectionRetry attempt=%d' % attempts + continue + raise e + def _reconnect(self): if self.connected: @@ -254,9 +287,9 @@ def _rollback(self): pass def close(self): - if self.connected: + if self.close_connection and self.connected: self.connection.close() - del self.connection del self.database + del self.connection self.connected = False pass From fc00b995e2c192f29435fa5b89fa4bffcc528dfc Mon Sep 17 00:00:00 2001 From: Anand Ganapathy Date: Thu, 9 Apr 2015 16:13:35 -0700 Subject: [PATCH 07/10] refs#19069 run a query to ensure connection truly fails --- django_mongodb_engine/base.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/django_mongodb_engine/base.py b/django_mongodb_engine/base.py index a090790c..ef282781 100644 --- a/django_mongodb_engine/base.py +++ b/django_mongodb_engine/base.py @@ -250,6 +250,9 @@ def pop(name, default=None): self.connected = True connection_created.send(sender=self.__class__, connection=self) + ''' execute a quick sample query so that the failure will happen noticed on EoE + that auth succeeds on switchover but command fails ''' + self.database['system.users'].find_one() break except Exception as e: print 'MongoConnectionFailure ', str(e) From 7408e84ffce3e38b9c7438172ed13eb1e9b23636 Mon Sep 17 00:00:00 2001 From: Anand Ganapathy Date: Wed, 19 Aug 2015 11:44:11 -0700 Subject: [PATCH 08/10] refs#26219 change retry interval; log database name --- django_mongodb_engine/base.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/django_mongodb_engine/base.py b/django_mongodb_engine/base.py index ef282781..68f8efb1 100644 --- a/django_mongodb_engine/base.py +++ b/django_mongodb_engine/base.py @@ -191,7 +191,7 @@ def __init__(self, *args, **kwargs): ''' number of times to retry the connection on failure ''' self.conn_retries = kwargs.pop('conn_retries', 10) ''' time to sleep between retries ''' - self.conn_sleep_interval = kwargs.pop('conn_sleep_interval', 2) + self.conn_sleep_interval = kwargs.pop('conn_sleep_interval', 5) del self.connection def get_collection(self, name, **kwargs): @@ -250,12 +250,14 @@ def pop(name, default=None): self.connected = True connection_created.send(sender=self.__class__, connection=self) - ''' execute a quick sample query so that the failure will happen noticed on EoE - that auth succeeds on switchover but command fails ''' + ''' execute a quick sample query so that the failure will happen + on the command that is run after the switchover, auth succeeds + on secondary but commands cannot be run. This command will + throw an exception and hence we will attempt to reconnect again ''' self.database['system.users'].find_one() break except Exception as e: - print 'MongoConnectionFailure ', str(e) + print 'MongoConnectionFailure to database %s %s' % (db_name,str(e)) print traceback.format_exc() ''' Make sure we set connected to False just in case we failed on the send ''' From ad28127ebb1831100c821d560a37178e41c0db3e Mon Sep 17 00:00:00 2001 From: Anand Ganapathy Date: Wed, 7 Oct 2015 22:59:38 +0000 Subject: [PATCH 09/10] refs#28750 : fix the call to system.indexes as mongo 2.6 disallows users query --- django_mongodb_engine/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/django_mongodb_engine/base.py b/django_mongodb_engine/base.py index 68f8efb1..45567303 100644 --- a/django_mongodb_engine/base.py +++ b/django_mongodb_engine/base.py @@ -254,7 +254,7 @@ def pop(name, default=None): on the command that is run after the switchover, auth succeeds on secondary but commands cannot be run. This command will throw an exception and hence we will attempt to reconnect again ''' - self.database['system.users'].find_one() + self.database['system.indexes'].find_one() break except Exception as e: print 'MongoConnectionFailure to database %s %s' % (db_name,str(e)) From 90afaf2bdc9e7506c511e27d8d0269061ce553c3 Mon Sep 17 00:00:00 2001 From: Anand Ganapathy Date: Sat, 17 Oct 2015 00:23:26 +0000 Subject: [PATCH 10/10] refs#29422: remove the retries and let each request be retried at end user level to not delay the request --- django_mongodb_engine/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/django_mongodb_engine/base.py b/django_mongodb_engine/base.py index 45567303..ff918a66 100644 --- a/django_mongodb_engine/base.py +++ b/django_mongodb_engine/base.py @@ -189,7 +189,7 @@ def __init__(self, *args, **kwargs): ''' this dictates if we want to close connection at the end of each request or cache it (old behavior) ''' self.close_connection = kwargs.pop('close_connection', True) ''' number of times to retry the connection on failure ''' - self.conn_retries = kwargs.pop('conn_retries', 10) + self.conn_retries = kwargs.pop('conn_retries', 1) ''' time to sleep between retries ''' self.conn_sleep_interval = kwargs.pop('conn_sleep_interval', 5) del self.connection