-
Notifications
You must be signed in to change notification settings - Fork 91
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ConnectionError for deferreds waiting for connection #89
base: master
Are you sure you want to change the base?
ConnectionError for deferreds waiting for connection #89
Conversation
Call errback with ConnectionError of deferreds waiting for connection in ConnectionHandler's wrapper when all attempts for connecting fail.
Haven't tested this code but I'm not too sure about it. The concern is about a reconnection attempt calling errback more than once, and failing. |
I thing calling errback more than once won't happen because RedisFactory.deferred is set to None after errback and is called only when there is no connection in pool. Because there is 1:1 relation between RedisFactory and ConnectionHandler (I haven't found another case) there is no other way to call factory's errback when connection fail. In ConnectionHandler, deferred is put to waiting set only when factory's deferred has called == False. |
Good, will let this sit for another day to see if anyone else has concerns, otherwise will merge in. |
Here is example script that explain (I hope) what I expect from this patch. #!/usr/bin/env python
import sys
from twisted.internet import defer, reactor, task
from twisted.python import log
from txredisapi import lazyConnectionPool
pool = None
def newPool():
global pool
pool = lazyConnectionPool('localhost', 6379, connectTimeout=1, poolsize=2)
log.msg('New pool: %s' % pool)
pool._factory.maxRetries = 5
def reconnectPool(res, delay):
global pool
log.msg('Connection failed after %s attempts: %s' % (pool._factory.retries - 1, res.getErrorMessage()))
log.msg('Will create new pool after %s seconds' % delay)
reactor.callLater(delay, newPool)
def doWork(batch_id):
global pool
@defer.inlineCallbacks
def ping(task_id):
try:
yield pool.ping()
except Exception as e:
log.msg('Ping #%s.%s: %s %s' % (batch_id, task_id, type(e), str(e)))
log.msg('Running doWork batch #%s' % batch_id)
defers = []
for i in range(10):
d = ping(i)
defers.append(d)
return defer.DeferredList(defers)
@defer.inlineCallbacks
def test():
global pool
reconnectDelay = 10
try:
newPool()
pool._connected.addErrback(reconnectPool, reconnectDelay)
yield doWork(0)
yield doWork(1)
yield task.deferLater(reactor, reconnectDelay + 1, lambda: None)
yield doWork(2)
yield doWork(3)
except Exception as e:
print type(e), str(e)
finally:
reactor.stop()
log.startLogging(sys.stdout)
reactor.suggestThreadPoolSize(1)
reactor.callWhenRunning(test)
reactor.run() And its result:
Batch 0 failed because of new code and batch 1 because pool is not connected (and don't try connect). Then I create new pool and run batchs 2 and 3, their behaviour is same as 0 and 1. I've fixed cancelWaiting because it discarded the failure. |
Call errback with ConnectionError of deferreds waiting for connection
in ConnectionHandler's wrapper when all attempts for connecting fail.