我正在努力在使用 Deferred 对象的 Web 服务代码中产生与不使用 Deferred 对象的代码相同的行为。我的目标是编写一个装饰器,它将任何方法(与 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
当所有 raise 语句都被注释掉时,将向浏览器显示一个 HTML 文档,并在包含标记为“E5”的 raise 语句时显示一个格式良好的堆栈跟踪(Twisted 为我做的)。这就是我想要的。同样,如果我根本不使用 Deferred 对象并将来自 callback1 和 callback2 的所有行为放在 render_GET() 中,render_GET 中任何地方引发的异常都会产生所需的堆栈跟踪。
我正在尝试编写将立即响应浏览器的代码,不会导致 Twisted 内的资源泄漏,并且在包含任何 raise 语句“E1”到“E3”的情况下也会显示浏览器堆栈跟踪。延迟代码——当然我知道堆栈跟踪本身会有所不同。(我不太关心“E4”案例。)在阅读了本网站上的 Twisted 文档和其他问题后,我不确定如何实现这一点。我原以为添加 errback 应该会促进这一点,但显然不是。一定有一些关于 Deferred 对象和 twisted.web 堆栈的东西我不理解。
我在此处记录的日志记录效果可能会受到我使用 PythonLoggingObserver 将 Twisted 日志记录连接到标准日志记录模块的影响。
当包含“E1”时,浏览器会一直等待,直到反应器关闭,此时会记录带有堆栈跟踪的 ValueError 异常,并且浏览器会收到一个空文档。
当包含“E2”时,会立即记录带有堆栈跟踪的 ValueError 异常,但浏览器会等待直到反应器关闭,此时它会收到一个空文档。
当包含“E3”时,立即记录带有堆栈跟踪的 ValueError 异常,浏览器等待直到反应器关闭,然后接收预期的文档。
当包含 raise 语句“E4”时,预期的文档会立即返回给浏览器,并立即记录带有堆栈跟踪的 ValueError 异常。(在这种情况下是否存在资源泄漏的可能性?)