Pergunta

Eu estou lutando para produzir o mesmo comportamento em serviço da web de código que usa Diferidos objetos como no código que não.Meu objetivo é escrever um profissional que irá delegar o processamento de qualquer método (que é dissociado da Torcida) para a Torcida pool de threads, de modo que o reator não é bloqueado, sem alterar o método da semântica.

Quando uma instância da classe echo abaixo é exposta como um serviço da web, este código:

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

vai exibir um documento HTML para o browser quando todas as levantar demonstrações são comentados, e apresentar uma bem formatada rastreamento de pilha (que Torcida não para mim) quando a levantar instrução rotulada "E5" está incluído.É isso que eu quero.Da mesma forma, se eu não usar o Diferidos os objetos e coloque todo o comportamento de callback1 e callback2 dentro render_GET(), uma exceção é levantada em qualquer lugar dentro render_GET vai produzir o desejado de rastreamento de pilha.

Eu estou tentando escrever código que irá responder para o navegador imediatamente, para não causar vazamentos de recurso no prazo de Torcida, e fazer com que o navegador rastreamento de pilha para também ser apresentada nos casos em que qualquer uma das levantar demonstrações "E1" a "E3" é incluído no diferido código-embora, claro, eu entendo que os rastreamentos de pilha si vai ser diferente.(O "E4" caso eu não me preocupo tanto.) Depois de ler a Torcida documentação e outras questões sobre este site eu estou certo de como conseguir isso.Eu teria pensado que a adição de um errback deve facilitar isso, mas, evidentemente, não.Há algo sobre Diferidos objetos e a torcida.pilha da web que eu não estou entendendo.

Os efeitos no log I documento aqui pode ser afetada pelo uso da PythonLoggingObserver a ponte Torcida do log para o padrão do módulo de registo.

Quando "E1" é incluído, o navegador aguarda até que o reator é desligado, no ponto em que a exceção ValueError com rastreamento de pilha é registrado e o navegador recebe um documento vazio.

Quando "E2" é incluído, a exceção ValueError com rastreamento de pilha é registada imediatamente, mas o navegador aguarda até que o reator é desligado em que ponto ele recebe um documento vazio.

Quando "E3" é incluído, a exceção ValueError com rastreamento de pilha é registada imediatamente, o navegador aguarda até que o reator é desligado, e em um ponto em que recebe o documento pretendido.

Quando levantar instrução "E4" é incluído, o documento pretendido for retornado para o navegador imediatamente, e a exceção ValueError com rastreamento de pilha é registada imediatamente.(Não há qualquer possibilidade de uma fuga de recursos, neste caso?)

Foi útil?

Solução

Ok, depois de ler a sua pergunta várias vezes, eu acho que eu entendo o que o seu pedindo.Eu também reformulado o código para fazer um pouco melhor do que o original de resposta.Esta nova resposta deve mostrar todos os poderes dos créditos do.

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

Também recomendo que você leia o krondo tutorial.Ele irá te ensinar tudo que você precisa saber sobre diferidos.

Editar:

Ter modificado o código acima para correção de alguns erros bobos.Também melhorá-lo.Se uma exceção acontece em qualquer lugar (exceto em self.errback, mas precisamos de algum nível de confiança), em seguida, ele será passado para self.errback o que será de registo ou imprimir o erro na torcida e, em seguida, enviar o rastreamento para o navegador e fechar o pedido.Isso deve parar de quaisquer fugas de recursos.

Outras dicas

Eu descobri por escavando a Torcida de origem.O discernimento necessário é que o reator e Diferidos de retorno de chamada/errback cadeia lógica é dissociado do objeto do pedido, que é como os dados que recebe de volta para o navegador.O errback é necessário, mas não pode simplesmente propagar a Falha objeto para a cadeia como no original, o código que eu postei.O errback deve relatar o erro para o navegador.

O código abaixo, atende todas as minhas necessidades (nunca mantém o navegador espera, sempre dá o rastreamento de pilha, não necessita de um reator de reiniciar para começar as coisas de novo) e vai permitir-me para decorar o bloqueio de métodos e, assim, delegar a threads para manter o reator ágil para outros eventos (tais métodos serão, essencialmente, tomar o lugar de callback1 aqui).No entanto, eu achei que no código abaixo, descomentando a "E4" levantar a instrução produz muito estranho comportamento em futuras solicitações de navegador (dados parciais de pedidos anteriores retornado para o navegador;deadlock).

Esperemos que os outros vão achar que este é um útil Diferidos exemplo.

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
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top