IlyaSkriblovsky/txredisapi

Killing an application with a subscriber factory yields a non clean shutdown

ansman opened this issue · 6 comments

If you run the subscriber.py example and kill the server with ctrl+c you get the following:

2013-09-11 23:29:43-0700 [-] Log opened.
2013-09-11 23:29:43-0700 [-] twistd 13.0.0 (/Users/nicklas/.wrapp/virtualenvs/wrapport/bin/python2.7 2.7.5) starting up.
2013-09-11 23:29:43-0700 [-] reactor class: twisted.internet.selectreactor.SelectReactor.
2013-09-11 23:29:43-0700 [-] Starting factory <__builtin__.myFactory instance at 0x10a8850e0>
2013-09-11 23:29:43-0700 [Uninitialized] waiting for messages...
2013-09-11 23:29:43-0700 [Uninitialized] use the redis client to send messages:
2013-09-11 23:29:43-0700 [Uninitialized] $ redis-cli publish zz test
2013-09-11 23:29:43-0700 [Uninitialized] $ redis-cli publish foo.bar hello world
2013-09-11 23:29:43-0700 [-] pattern=subscribe, channel=zz message=1
2013-09-11 23:29:43-0700 [-] pattern=psubscribe, channel=foo.* message=2
^C2013-09-11 23:29:45-0700 [-] Received SIGINT, shutting down.
2013-09-11 23:29:45-0700 [myProtocol,client] lost connection: [Failure instance: Traceback (failure with no frames): <class 'twisted.internet.error.ConnectionLost'>: Connection to the other side was lost in a non-clean fashion: Connection lost.
2013-09-11 23:29:45-0700 [myProtocol,client] ]
2013-09-11 23:29:45-0700 [myProtocol,client] <twisted.internet.tcp.Connector instance at 0x10a515b90> will retry in 3 seconds
2013-09-11 23:29:45-0700 [myProtocol,client] Stopping factory <__builtin__.myFactory instance at 0x10a8850e0>
2013-09-11 23:29:45-0700 [-] Main loop terminated.
2013-09-11 23:29:45-0700 [-] Server Shut Down.

Is there any way to prevent this "non clean" shutdown?
It would be kinda nice to be able to wait for all pending requests to finish before closing it.

I can add that this doesn't happen when using redis.Connection.

I think one way to prevent this non-clean shutdown would be to handle signals and make your software wait for all redis commands to be finished before closing the connection. It shouldn't be handled in the library.

Regarding redis.Connection, it's the very same code therefore should be no difference.

I don't really agree.
When stopping a factory you can gracefully stop all connections, it's all built in to twisted.

Also, perhaps it should be the same with redis.Connection but it's not if you try it.

What's your suggestion to fix it?

I'll do some investigation and get back to you. Thanks for being open minded :)

Ok, I'm going to close this one.

Here is the solution I came up with (you have to use a service instead of an application):

import txredisapi as redis

from twisted.internet import reactor, defer
from twisted.application import service


class myProtocol(redis.SubscriberProtocol):
    def connectionMade(self):
        # This is important, otherwise  self.factory.handler.disconnect() is a noop
        self.factory.addConnection(self)
        # ...

    def messageReceived(self, pattern, channel, message):
        pass

    def connectionLost(self, reason):
        self.factory.delConnection(self)
        print "lost connection:", reason


class myFactory(redis.SubscriberFactory):
    # SubscriberFactory is a wapper for the ReconnectingClientFactory
    maxDelay = 120
    continueTrying = True
    protocol = myProtocol


class SubscriberService(service.Service):
    @defer.inlineCallbacks
    def startService(self):
        self.factory = myFactory()
        yield reactor.connectTCP('localhost', 6379, self.factory)

    def stopService(self):
        # This should return a deferred that fires when the shutdown is complete
        return self.factory.handler.disconnect()


application = service.Application("subscriber")
SubscriberService().setServiceParent(application)

Which yields the output:

2013-09-12 17:15:50-0700 [-] Log opened.
2013-09-12 17:15:50-0700 [-] twistd 13.0.0 (/Users/nicklas/.wrapp/virtualenvs/wrapport/bin/python2.7 2.7.5) starting up.
2013-09-12 17:15:50-0700 [-] reactor class: twisted.internet.selectreactor.SelectReactor.
2013-09-12 17:15:50-0700 [-] Starting factory <__builtin__.myFactory instance at 0x10fda2dd0>
^C2013-09-12 17:15:51-0700 [-] Received SIGINT, shutting down.
2013-09-12 17:15:51-0700 [myProtocol,client] lost connection: [Failure instance: Traceback (failure with no frames): <class 'twisted.internet.error.ConnectionDone'>: Connection was closed cleanly.
2013-09-12 17:15:51-0700 [myProtocol,client] ]
2013-09-12 17:15:51-0700 [myProtocol,client] Stopping factory <__builtin__.myFactory instance at 0x10fda2dd0>
2013-09-12 17:15:52-0700 [-] Main loop terminated.
2013-09-12 17:15:52-0700 [-] Server Shut Down.

Cool. Feel free to send a pull request if you'd like to add that to the readme.

On Sep 12, 2013, at 8:16 PM, Nicklas Ansman Giertz notifications@github.com wrote:

Ok, I'm going to close this one.

Here is the solution I came up with (you have to use a service instead of an application):

import txredisapi as redis

from twisted.internet import reactor, defer
from twisted.application import service

class myProtocol(redis.SubscriberProtocol):
def connectionMade(self):
self.factory.addConnection(self)
# ...

def messageReceived(self, pattern, channel, message):
    pass

def connectionLost(self, reason):
    self.factory.delConnection(self)
    print "lost connection:", reason

class myFactory(redis.SubscriberFactory):
# SubscriberFactory is a wapper for the ReconnectingClientFactory
maxDelay = 120
continueTrying = True
protocol = myProtocol

class SubscriberService(service.Service):
@defer.inlineCallbacks
def startService(self):
self.factory = myFactory()
yield reactor.connectTCP('localhost', 6379, self.factory)

def stopService(self):
    # This should return a deferred that fires when the shutdown is complete
    return self.factory.handler.disconnect()

application = service.Application("subscriber")
SubscriberService().setServiceParent(application)
Which yields the output:

2013-09-12 17:15:50-0700 [-] Log opened.
2013-09-12 17:15:50-0700 [-] twistd 13.0.0 (/Users/nicklas/.wrapp/virtualenvs/wrapport/bin/python2.7 2.7.5) starting up.
2013-09-12 17:15:50-0700 [-] reactor class: twisted.internet.selectreactor.SelectReactor.
2013-09-12 17:15:50-0700 [-] Starting factory <builtin.myFactory instance at 0x10fda2dd0>
^C2013-09-12 17:15:51-0700 [-] Received SIGINT, shutting down.
2013-09-12 17:15:51-0700 [myProtocol,client] lost connection: [Failure instance: Traceback (failure with no frames): <class 'twisted.internet.error.ConnectionDone'>: Connection was closed cleanly.
2013-09-12 17:15:51-0700 [myProtocol,client] ]
2013-09-12 17:15:51-0700 [myProtocol,client] Stopping factory <builtin.myFactory instance at 0x10fda2dd0>
2013-09-12 17:15:52-0700 [-] Main loop terminated.
2013-09-12 17:15:52-0700 [-] Server Shut Down.

Reply to this email directly or view it on GitHub.