I have a code which works fine for one user request. However, it can not handle multiple requests, it waits for one requests to finish and then handles second requests. How can I handle multiple requests concurrently.
import tornado.ioloop
import tornado.web
import tornado.websocket
from tornado import gen
import random
import time
import sys
This is a class that simulates some incoming data.
class Message():
def __init__(self):
self.dct = {'foo': 0, 'bar': 0, 'durrr': 0}
self.keys = list(self.dct.keys())
def update_key(self):
dct_key = random.choice(self.keys)
ran = random.choice(range(10, 21))
self.dct[dct_key] += ran
if self.dct[dct_key] >= 100:
self.dct[dct_key] = 'Loading Completed'
self.keys.remove(dct_key)
def is_completed(self):
return True if self.keys == [] else False
def __str__(self):
strng = ''
for key, value in self.dct.items():
if type(value) == int:
strng += '{}: {}% completed.<br>'.format(key, value)
else:
strng += '{}: {}<br>'.format(key, value)
return strng
This class sends data through socket.
class EchoWebSocket(tornado.websocket.WebSocketHandler):
def open(self):
print("WebSocket opened")
def on_message(self, message):
msg = Message()
while not msg.is_completed():
msg.update_key()
try:
fut = self.write_message('Download progress for user xyz:<br>{}Download in progress! Please wait...<br>'.format(msg.__str__()))
print(fut)
except tornado.websocket.WebSocketClosedError:
print('WebSocket is closed')
break
time.sleep(1)
self.write_message('Download progress for user xyz:<br>{}Download completed. You may proceed.'.format(msg.__str__()))
#sys.exit('Program terminated.')
def on_close(self):
print("WebSocket closed")
Main class is simple. Renders some html. The main engine is in EchoWebSocket.
class Main(tornado.web.RequestHandler):
def get(self):
self.render('counter2.html', title='Websockets')
application = tornado.web.Application([
(r"/", Main),
(r"/websocket", EchoWebSocket),
])
if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
And the html:
<!doctype html>
<html>
<head>
<title>Tornado Test</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.js"></script>
</head>
<body>
<script>
$(document).ready(function () {
var ws = new WebSocket("ws://localhost:8888/websocket");
ws.onopen = function() {
ws.send("Hello, world");
};
ws.onmessage = function (evt) {
document.getElementById("myDIV").innerHTML = evt.data + "<br>";
};
});
</script>
<div id="myDIV"></div>
</body>
</html>
You're using time.sleep(1)
. But time.sleep
is a blocking function, that means it will stop the whole server and nothing else will be able to run during that time.
This has also been mentioned in Tornado FAQs
page.
What you need is an asynchronous sleep function. Tornado has gen.sleep
. Use it like this:
async def my_func():
...
await gen.sleep(1)