I am using python Klein http://klein.readthedocs.io/en/latest/ for setting up a web service. I had checked the documentation but I still don't know how to set the timeout of the service. Can anyone who is more familiar with tool shows how to set the timeout to 15 seconds? Thanks!
You could call Request.loseConnection()
to drop the request connection to the client after an set timeout interval. Here is a quick example:
from twisted.internet import reactor, task, defer
from klein import Klein
app = Klein()
request_timeout = 10 # seconds
@app.route('/delayed/<int:n>')
@defer.inlineCallbacks
def timeoutRequest(request, n):
work = serverTask(n) # work that might take too long
drop = reactor.callLater(
request_timeout, # drop request connection after n seconds
dropRequest, # function to drop request connection
request, # pass request obj into dropRequest()
work) # pass worker deferred obj to dropRequest()
try:
result = yield work # work has completed, get result
drop.cancel() # cancel the task to drop the request connection
except:
result = 'Request dropped'
defer.returnValue(result)
def serverTask(n):
"""
A simulation of a task that takes n number of seconds to complete.
"""
d = task.deferLater(reactor, n, lambda: 'delayed for %d seconds' % (n))
return d
def dropRequest(request, deferred):
"""
Drop the request connection and cancel any deferreds
"""
request.loseConnection()
deferred.cancel()
app.run('localhost', 9000)
To try this out, go to http://localhost:9000/delayed/2
then http://localhost:9000/delayed/20
to test a scenario when the task doesn't complete in time. Don't forget to cancel all tasks, deferreds, threads, etc related to this request or you could potentially waste lots of memory.
Server Side Task: Client goes to /delayed/<n>
endpoint with a specified delay value. A server side task (serverTask()
) starts and for the sake of simplicity and to simulate a busy task, deferLater
was used to return a string after n
seconds.
Request Timeout: Using callLater
function, after the request_timeout
interval, call the dropRequest
function and pass request
and all work deferreds that need to be canceled (in this case there's only work
). When the request_timeout
has passed then the request connection will be closed (request.loseConnection()
) and deferreds will be cancelled (deferred.cancel
).
Yield Server Task Result: In a try/except block, the result will be yielded when the value is available or, if the timeout has passed and connection is dropped, an error will occur and the Request dropped
message will be returned.
This really doesn't seem like a desirable scenario and should be avoided if possible, but I could see a need for this kind of functionality. Also, though rare, keep in mind that loseConnection
doesn't always fully close a connection (this is due to TCP implementation not so much Twisted). A better solution would be to cancel a server side task when the client disconnects (which may be a bit easier to catch). This can be done by attaching an addErrback
to Request.notifyFinish()
. Here is an example using just Twisted (http://twistedmatrix.com/documents/current/web/howto/web-in-60/interrupted.html).