Question

I'm trying to put slow computations inside threads, and getting an error "Request.write called on a request after Request.finish was called."

I've looked through answers already, and find exact the same question, but the solution not working for me. Please advise.

from twisted.web.server import Site, NOT_DONE_YET
from twisted.web.resource import Resource
from twisted.internet import reactor, threads
from twisted.python import log

import sys
import time


def SlowComputation():
    time.sleep(10)
    return "Lang Computation Result"


def FastComputation():
    return "Fast Computation Result"


class PerformComputation(Resource):
    def Success(self, request):
        request.write('Success')
        request.finish()

    def Failure(self, request):
        request.write('Failure')
        request.finish()

    def render_GET(self, request):
        if 'fast' in request.args:
            d = threads.deferToThread(FastComputation)
            d.addCallback(self.Success(request))
            return NOT_DONE_YET
        if 'slow' in request.args:
            d = threads.deferToThread(SlowComputation)
            d.addCallback(self.Success(request))
            return NOT_DONE_YET


log.startLogging(sys.stdout)
root = Resource()
root.putChild("calculate", PerformComputation())
factory = Site(root)
reactor.listenTCP(8880, factory, interface='localhost')
reactor.run()
Was it helpful?

Solution

This:

d.addCallback(self.Success(request))

is the same as:

temp = self.Success(request)
d.addCallback(temp)

which, given the definition of Success is the same as:

request.write('Success')
request.finish()
temp = None
d.addCallback(None)

This probably fails with Request.write called on a request after Request.finish was called. because d.addCallback(None) raises an exception and the server tries to report the error as the response. However, since finish has already been called it can't write the error.

The correct way to add a callback to a Deferred with an extra argument is d.addCallback(self.Success, request). Callbacks on a Deferred always get passed the result of the Deferred as the first argument, though - so the correct signature for Success is:

def Success(self, result, request):
    ...
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top