我正在实现一个库模块,作为couchdb更改通知的客户端。我想让库处于“连续”模式,也就是说,连接必须永远保持打开状态,或者至少如果连接已经关闭则必须重新连接,以便couchdb有一个通道来通知发生的任何新变化。数据库。然后我将处理这些通知以生成某些事件(这尚未实现)。
我选择的方法是使用ReconnectingClientFactory(按照精心设计的算法自动重新连接)作为我的协议工厂的基础。无论何时建立连接,都会调用buildProtocol方法。在这个方法中,我创建协议实例,并激活一个callLater(立即)以表示连接已准备就绪。在cdConnected函数中,我发送请求并添加一个回调来处理接收到的数据(cbReceived)。
代码按预期重新连接,但我遇到两个不同的问题:
也许有人知道我做错了什么?
谢谢!
(编辑:“连接已完全关闭。”错误由我自己打印,因此可以忽略)
以下是代码:
from twisted.internet import defer
from twisted.internet.protocol import ReconnectingClientFactory
from twisted.web._newclient import HTTP11ClientProtocol
from twisted.web._newclient import Request
from twisted.web.client import _parse
class MyReconnectingClientFactory(ReconnectingClientFactory):
def __init__(self, reactor, cbConnected):
self.reactor = reactor
self.cbConnected = cbConnected
def startedConnecting(self, connector):
print 'Started to connect ...'
def buildProtocol(self, addr):
print 'Resetting reconnection delay'
self.resetDelay()
proto = HTTP11ClientProtocol()
self.reactor.callLater(0, self.cbConnected, proto)
return proto
def clientConnectionLost(self, connector, reason):
print 'Lost connection. Reason:', reason
ReconnectingClientFactory.clientConnectionLost(self, connector, reason)
def clientConnectionFailed(self, connector, reason):
print 'Connection failed. Reason:', reason
ReconnectingClientFactory.clientConnectionFailed(self, connector, reason)
def cbReceived(response):
print response
def printError(failure):
print "printError > %s" % (str(failure))
def cbConnected(proto):
print "Sending request ..."
req = Request(method, path, headers, bodyProducer)
d = proto.request(req)
d.addCallback(cbReceived).addErrback(printError)
return d
from twisted.internet import reactor
uri='http://localhost:5984/cn/_changes?feed=continuous'
method='GET'
headers=None
bodyProducer=None
scheme, host, port, path = _parse(uri)
factory = MyReconnectingClientFactory(reactor, cbConnected)
reactor.connectTCP(host, port, factory)
reactor.run()
这是输出:
Started to connect ...
Resetting reconnection delay
Sending request ...
printError > [Failure instance: Traceback (failure with no frames): <class 'twisted.web._newclient.RequestGenerationFailed'>: [<twisted.python.failure.Failure <type 'exceptions.AttributeError'>>]
]
Lost connection. Reason: [Failure instance: Traceback (failure with no frames): <class 'twisted.internet.error.ConnectionDone'>: Connection was closed cleanly.
]
Started to connect ...
Resetting reconnection delay
Sending request ...
printError > [Failure instance: Traceback (failure with no frames): <class 'twisted.web._newclient.RequestGenerationFailed'>: [<twisted.python.failure.Failure <type 'exceptions.AttributeError'>>]
]
Lost connection. Reason: [Failure instance: Traceback (failure with no frames): <class 'twisted.internet.error.ConnectionDone'>: Connection was closed cleanly.
]
答案 0 :(得分:5)
您应该查看生成的故障。 _newclient有抛出复合失败的习惯;这些包含进一步的失败。
我稍微修改了你的代码:
def printError(failure):
print "printError > %r" % failure
from twisted.web import _newclient
if failure.check(_newclient.RequestGenerationFailed):
print "printError: RequestGenerationFailed"
for f in failure.value.reasons:
print "printError > %r" % f
print f.getTraceback()
你在失败时做了str(),这不是获取异常信息的好方法。让repr照顾它,这是它的工作。
使用%r,我看到它实际上是在给我一个RequestGenerationFailed。这是一个更有趣的失败。失败的价值有原因。
通过我的修改,脚本给出了这个:
Started to connect ...
Resetting reconnection delay
Sending request ...
printError > <twisted.python.failure.Failure <class 'twisted.web._newclient.RequestGenerationFailed'>>
printError: RequestGenerationFailed
printError > <twisted.python.failure.Failure <type 'exceptions.AttributeError'>>
Traceback (most recent call last):
File "/usr/lib64/python2.7/site-packages/twisted/internet/base.py", line 1174, in mainLoop
self.runUntilCurrent()
File "/usr/lib64/python2.7/site-packages/twisted/internet/base.py", line 796, in runUntilCurrent
call.func(*call.args, **call.kw)
File "so.py", line 50, in cbConnected
d = proto.request(req)
File "/usr/lib64/python2.7/site-packages/twisted/web/_newclient.py", line 1266, in request
_requestDeferred = maybeDeferred(request.writeTo, self.transport)
--- <exception caught here> ---
File "/usr/lib64/python2.7/site-packages/twisted/internet/defer.py", line 125, in maybeDeferred
result = f(*args, **kw)
File "/usr/lib64/python2.7/site-packages/twisted/web/_newclient.py", line 703, in writeTo
self._writeHeaders(transport, None)
File "/usr/lib64/python2.7/site-packages/twisted/web/_newclient.py", line 535, in _writeHeaders
hosts = self.headers.getRawHeaders('host', ())
exceptions.AttributeError: 'NoneType' object has no attribute 'getRawHeaders'
Lost connection. Reason: [Failure instance: Traceback (failure with no frames): <class 'twisted.internet.error.ConnectionDone'>: Connection was closed cleanly.
]
这应该能给你一个很好的线索,让你知道在哪里寻找你的实际问题。
顺便提一下,看看Paisley,CouchDB的Twisted客户端:paisley
有一些分支,特别是my changes branch有一些您可能感兴趣的变更通知内容。我制作了一个桌面小程序,向我展示了添加到基于CouchDB的待办系统的任务。
听起来你的改变是a)已经在那里或b)应该去那里; c)你应该考虑与佩斯利合作并做出贡献。
祝你好运!