Friday, September 26, 2014

some suggested code change in Django 1.6.7



=========

I am not certain where to post or ask this question. If this is not the right forum, I apologize, and would appreciate if someone forwards it to the right one. In that case, just send me a note where I should watch for updates on this.

=========

 

This is not a feature request per se, but it is not exactly a bug report either.

 

We are recently upgrading from Django 1.5 to Django 1.6.7. One other relevant package version of interest is psycopg2 which is at 2.5.4.

 

After upgrade, many test cases were failing with the classic "InterfaceError: connection already closed" originating from psycopg2. Here is a typical stack trace in which user-name and app-name have been obscured.

 

 

  File "/home/user1/sme-appname/src/session_csrf/__init__.py", line 68, in process_view

    token = cache.get(PREFIX + key, '')

  File "/home/user1/sme-appname/lib/python2.7/site-packages/django/core/cache/backends/db.py", line 61, in get

    cursor = connections[db].cursor()

  File "/home/user1/sme-appname/lib/python2.7/site-packages/django/db/backends/__init__.py", line 162, in cursor

    cursor = util.CursorWrapper(self._cursor(), self)

  File "/home/user1/sme-appname/lib/python2.7/site-packages/django/db/backends/__init__.py", line 134, in _cursor

    return self.create_cursor()

  File "/home/user1/sme-appname/lib/python2.7/site-packages/django/db/utils.py", line 99, in __exit__

    six.reraise(dj_exc_type, dj_exc_value, traceback)

  File "/home/user1/sme-appname/lib/python2.7/site-packages/django/db/backends/__init__.py", line 134, in _cursor

    return self.create_cursor()

  File "/home/user1/sme-appname/lib/python2.7/site-packages/django/db/backends/postgresql_psycopg2/base.py", line 138, in create_cursor

    cursor = self.connection.cursor()

InterfaceError: connection already closed

 

I posted this on psycopg2 mailing list, but was told to contact you Django guys. Anyway, after tinkering around with some code in the django/db directory, I generated the following "fix" that helped most of our test cases to pass. The fix is in two files:

 

(1) django/db/backends/__init__.py   --> comment out the code that compares two autocommit values.

 

    def close_if_unusable_or_obsolete(self):

        """

        Closes the current connection if unrecoverable errors have occurred,

        or if it outlived its maximum age.

        """

        if self.connection is not None:

            # If the application didn't restore the original autocommit setting,

            # don't take chances, drop the connection.

            #if self.get_autocommit() != self.settings_dict['AUTOCOMMIT']:

            #    print("---- from within close_if_unusable_or_obsolete method ----")

            #    print("---- two autocommit settings not equal ----")

            #    print(self.get_autocommit())

            #    print(self.settings_dict['AUTOCOMMIT'])

            #    self.close()

            #    return

 

            if self.errors_occurred:

                if self.is_usable():

                    self.errors_occurred = False

                else:

                    print("---- from within close_if_unusable_or_obsolete method ----")

                    self.close()

                    return

 

            if self.close_at is not None and time.time() >= self.close_at:

                print("---- from within close_if_unusable_or_obsolete method ----")

                self.close()

                return

 

(2) django/db/__init__.py  --> simply call the recommended close_old_connections() as the comment in close_connection suggests, and comment out the old code.

 

 

def close_connection(**kwargs):

    #warnings.warn(

    #    "close_connection is superseded by close_old_connections.",

    #    PendingDeprecationWarning, stacklevel=2)

    ## Avoid circular imports

    #from django.db import transaction

    #for conn in connections:

    #    # If an error happens here the connection will be left in broken

    #    # state. Once a good db connection is again available, the

    #    # connection state will be cleaned up.

    #    transaction.abort(conn)

    #    print("---- from within close_connection method ----")

    #    connections[conn].close()

    close_old_connections()

 

 

I am not a Django expert, much less a Django/db expert. Could somebody investigate whether something like this can be done and released in Django 1.6.8? I am especially puzzled by why the two autocommit values are different. Should I do something else (in Django test client/settings/elsewhere) to make the two autocommit values the same? If this "fix" helps you guys, fine; we are interested in some proper fix coming from Django directly rather than patching things up ourselves.

 

Thanks,

Arun

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscribe@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at http://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/2c555f69-24f4-42fd-abea-8c24a50d3bc2%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

No comments:

Post a Comment