wbe*_*rry 8 python web-services twisted deferred
我正在努力在使用Deferred对象的Web服务代码中产生相同的行为,而不是在代码中.我的目标是编写一个装饰器,它将任何方法(从Twisted中解耦)的处理委托给Twisted线程池,这样反应器就不会被阻塞,而不会改变任何方法的语义.
当下面的类echo实例作为Web服务公开时,此代码:
from twisted.web import server, resource
from twisted.internet import defer, threads
from cgi import escape
from itertools import count
class echo(resource.Resource):
isLeaf = True
def errback(self, failure): return failure
def callback1(self, request, value):
#raise ValueError # E1
lines = ['<html><body>\n',
'<p>Page view #%s in this session</p>\n' % (value,),
'</body></html>\n']
return ''.join(lines)
def callback2(self, request, encoding):
def execute(message):
#raise ValueError # E2
request.write(message.encode(encoding))
#raise ValueError # E3
request.finish()
#raise ValueError # E4
return server.NOT_DONE_YET
return execute
def render_GET(self, request):
content_type, encoding = 'text/html', 'UTF-8'
request.setHeader('Content-Type', '%s; charset=%s' %
tuple(map(str, (content_type, encoding))))
s = request.getSession()
if not hasattr(s, 'counter'):
s.counter = count(1)
d = threads.deferToThread(self.callback1, request, s.counter.next())
d.addCallback(self.callback2(request, encoding))
d.addErrback(self.errback)
#raise ValueError # E5
return server.NOT_DONE_YET
Run Code Online (Sandbox Code Playgroud)
当所有的raise语句被注释掉时,它会向浏览器显示一个HTML文档,当包含标记为"E5"的raise语句时,它会显示格式良好的堆栈跟踪(Twisted为我做的).这就是我想要的.同样,如果我根本不使用Deferred对象并将callback1和callback2中的所有行为放在render_GET()中,则render_GET中任何位置引发的异常都将产生所需的堆栈跟踪.
我正在尝试编写将立即响应浏览器的代码,不会导致Twisted中的资源泄漏,并导致浏览器堆栈跟踪也显示在任何提升语句"E1"到"E3"包含在延迟代码 - 当然我理解堆栈跟踪本身会有所不同.("E4"案例我并不在乎.)在阅读Twisted文档和本网站上的其他问题之后,我不确定如何实现这一目标.我本以为添加一个错误应该可以促进这一点,但显然不是.必须有一些关于延迟对象和twisted.web堆栈的东西,我不理解.
这里对日志记录的影响可能会受到我使用PythonLoggingObserver将Twisted日志记录桥接到标准日志记录模块的影响.
当包含"E1"时,浏览器会等待反应堆关闭,此时会记录带有堆栈跟踪的ValueError异常,并且浏览器会收到一个空文档.
当包含"E2"时,会立即记录带有堆栈跟踪的ValueError异常,但浏览器会等待反应堆关闭,此时它会收到一个空文档.
当包含"E3"时,会立即记录带有堆栈跟踪的ValueError异常,浏览器会等待反应堆关闭,然后在此时收到目标文档.
当包含raise语句"E4"时,目标文档立即返回到浏览器,并立即记录带有堆栈跟踪的ValueError异常.(在这种情况下是否有资源泄漏的可能性?)
好吧,读了几遍你的问题后,我想我明白你在问什么了。我还修改了您的代码,使其比您原来的答案更好一些。这个新答案应该展示 deferred 的所有功能。
from twisted.web import server, resource
from twisted.internet import defer, threads
from itertools import count
class echo(resource.Resource):
isLeaf = True
def errback(self, failure, request):
failure.printTraceback() # This will print the trace back in a way that looks like a python exception.
# log.err(failure) # This will use the twisted logger. This is the best method, but
# you need to import twisted log.
request.processingFailed(failure) # This will send a trace to the browser and close the request.
return None # We have dealt with the failure. Clean it out now.
def final(self, message, request, encoding):
# Message will contain the message returned by callback1
request.write(message.encode(encoding)) # This will write the message and return it to the browser.
request.finish() # Done
def callback1(self, value):
#raise ValueError # E1
lines = ['<html><body>\n',
'<p>Page view #%s in this session</p>\n' % (value,),
'</body></html>\n']
return ''.join(lines)
#raise ValueError # E4
def render_GET(self, request):
content_type, encoding = 'text/html', 'UTF-8'
request.setHeader('Content-Type', '%s; charset=%s' %
tuple(map(str, (content_type, encoding))))
s = request.getSession()
if not hasattr(s, 'counter'):
s.counter = count(1)
d = threads.deferToThread(self.callback1, s.counter.next())
d.addCallback(self.final, request, encoding)
d.addErrback(self.errback, request) # We put this here in case the encoding raised an exception.
#raise ValueError # E5
return server.NOT_DONE_YET
Run Code Online (Sandbox Code Playgroud)
我还建议您阅读krondo教程。它将教您关于延迟需要了解的一切。
修改了上面的代码以修复一些愚蠢的错误。也对其进行了改进。如果异常发生在任何地方(除了 in 中self.errback,但我们需要一定程度的信任),那么它将被传递到self.errback,它将在twisted 中记录或打印错误,然后将跟踪发送到浏览器并关闭请求。这应该可以阻止任何资源泄漏。