Channels: Test Client causing "InterfaceError: connection already closed" on Postgresql

Created on 6 Jan 2017  路  6Comments  路  Source: django/channels

We're trying to upgrade from 0.17.3 to master to get the recent PendingMessageStore functionality and seeing a bunch of our tests using channels.tests.Client fail with an InterfaceError: connection already closed

I've tracked the error down to this commit: https://github.com/django/channels/commit/0ed04a9c06707388687bc85637baaf4909f88961

It appears after using the Client.consume method the consumer_finished signal is sent and subsequently django.db.close_old_connections ends up being called which closes the connection.
The next time that connection is used the InterfaceError is thrown

I'm not so clear this is a bug in channels, django or psycopg2 but I figured I would start here.
We've worked around the issue by deregistering the close_old_connections signal receiver in tests but this doesn't feel like an ideal solution.

I've pushed a branch demonstrating this error here: https://github.com/linuxlewis/channels/tree/bug/postgresql-interface-closed

Thank you for your time

bug exintermediate

Most helpful comment

Hah, Django does this to work around it:

def closing_iterator_wrapper(iterable, close):
    try:
        for item in iterable:
            yield item
    finally:
        request_finished.disconnect(close_old_connections)
        close()                                 # will fire request_finished
        request_finished.connect(close_old_connections)

I'll get something similar in now.

All 6 comments

Hm, that is weird, I've not been seeing that locally. Hopefully I'll get some time to investigate soon.

We are getting the same. I had to downgrade back to 0.17.3.

I've reproduced the issue across python2/3, ubuntu 14.04/16.04 and postgresql 9.5

Here's a snippet of my current work around for this issue.

# tests/base.py
from channels.signals import consumer_finished
from django.db import close_old_connections


class ChannelsTestMixin(object):

     def __init__(self, *args, **kwargs):
         super(ChannelsTestMixin, self).__init__(*args, **kwargs)
         consumer_finished.disconnect(close_old_connections)

class SomeFailingTestCase(ChannelsTestMixin, TestCase):
     pass

I'm seeing the same thing using Python 2.7.10, psycopg2 2.6.2, Django 1.10.5, channels 1.0.2, and postgresql 9.5.4 on OSX. The workaround from @linuxlewis is doing the trick for now.

Hah, Django does this to work around it:

def closing_iterator_wrapper(iterable, close):
    try:
        for item in iterable:
            yield item
    finally:
        request_finished.disconnect(close_old_connections)
        close()                                 # will fire request_finished
        request_finished.connect(close_old_connections)

I'll get something similar in now.

OK, that commit should fix it - let me know if things are still a problem.

Was this page helpful?
0 / 5 - 0 ratings