WebサービスにおけるTwisted Defered VSブロック
-
29-10-2019 - |
質問
遅延オブジェクトを使用するWebサービスコードでも同じ動作を生み出すのに苦労しています。私の目的は、その方法の意味論のいずれかを変更することなく、任意の方法(ツイストから切り離された)の処理を委任するデコレータを書くことです。
下記のクラスエコーのインスタンスが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
.
は、「E5」と表示されているRAISE文が含まれている場合に、すべてのRAIS文をコメントアウトしたときにHTML文書をブラウザに表示し、ジェネリードステートメントが含まれている場合には、正しいフォーマットされたスタックトレース(どちらがねじれている)を表示します。それが私が欲しいものです。同様に、繰り返しオブジェクトをまったく使用してRender_get()内のCallBack1とCallback2からすべての動作を配置しない場合、render_get内のどこにでも発生した例外が希望のスタックトレースを生成します。
ブラウザに直ちに応答するコードを書き込もうとしていて、ねじれ内のリソースリークを発生させず、階層ステートメント「E1」を「E3」にする場合にブラウザのスタックトレースも表示されます。もちろん、スタックトレース自体が異なることを理解していますが、もちろん私は理解しています。 (e4 "ケース私は気にしないのです。このサイトのツイストドキュメントやその他の質問を読みた後、私はこれを達成する方法がわからない。エレクトバックを追加するはずですが明らかにそうではないと思いました。私が理解していない遅延オブジェクトとTwisted.Webスタックについて何かがなければなりません。
ここでのロギングI文書への影響は、標準ロギングモジュールへのツイストロギングをブリッジするためのPythonLoggingObServerの私の使用の影響を受ける可能性があります。
"e1"が含まれている場合、ブラウザはリアクトルがシャットダウンされるまで待機します。その時点で、スタックトレースを使用したValueError例外が記録され、ブラウザは空の文書を受信します。
「e2」が含まれている場合、スタックトレースを使用したValueError例外がすぐにログに記録されますが、原子炉が空の文書を受信する時点で停止するまで待機します。
「E3」が含まれている場合、スタックトレースを使用したValueError例外がすぐにログに記録されていると、原子炉がシャットダウンされるまで待機し、その時点で意図した文書を受け取ります。
RAISE文「E4」が含まれている場合、目的の文書がすぐにブラウザに返され、スタックトレースを使用したValueErrorの例外がすぐに記録されます。 (この場合はリソースリークの可能性がありますか?)
解決
OK、あなたの質問を数回読んだ後、私はあなたが尋ねるものを理解していると思います。私はまたあなたの元の答えよりも少し良くするためにコードを修正しました。この新しい答えは延期のすべての力を披露するべきです。
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
.
また、 krondo チュートリアルを読むことをお勧めします。それはあなたが遅延について知る必要があるすべてをあなたに教えるでしょう。
編集:
上記のコードを修正して、愚かなバグを修正しました。改善しました。例外がどこにも発生した場合(self.errback
を除くが、ある程度の信頼が必要ですが、これはself.errback
に渡します。これはTwistedでエラーをログまたは印刷してから、トレースをブラウザに送信してからに送信します。リクエストを閉じます。これにより、リソースリークを停止する必要があります。
他のヒント
私はねじれ源を掘り下げることによってそれを出し出した。必要な洞察は、リセクタと延期コールバック/エレクトバックチェーンロジックがリクエストオブジェクトからデカップリングされているため、データがブラウザに戻る方法であることです。誤動作は必要ですが、投稿した元のコードのように障害オブジェクトをチェーンの下に伝播するだけではありません。 Errbackはブラウザにエラーを報告する必要があります。
下記のコードは私の要件を満たしています(絶対に待機しておく、常にスタックトレースを与えてください。他の事象に応答する反応器(そのような方法は本質的にここでCallback1の場所を取ります)。ただし、以下のコードでは、「E4」RASEステートメントが後続のブラウザ要求で非常に奇妙な動作を生成していることを確認しました(前の要求からの部分データはブラウザに返されます。デッドロック)。
他の人はこれを有用な繰延例であると思います。
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, request):
def execute(failure):
request.processingFailed(failure)
return failure
return execute
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)
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, s.counter.next())
eback = self.errback(request)
d.addErrback(eback)
d.addCallback(self.callback2(request, encoding))
d.addErrback(eback)
#raise ValueError # E5
return server.NOT_DONE_YET
.