我需要在Tornado服务器中处理一些长时间的请求。 我刚刚开始用Tornado了解异步代码的整个概念,似乎虽然这会让更多用户在处理我的长请求时与服务器进行交互,但它无法解决我的问题这是请求超时。
异步代码在服务器中异步工作,但客户端保持同步,这意味着虽然服务器可以处理更多请求,但客户端仍然会被卡住"等待响应,直到发生超时(我错了吗?)
问题是,如何解决浏览器超时问题? 换句话说,我正在寻找一种方法来从客户端发出请求,该请求将立即返回,但在后台处理请求。处理完成后,它应以某种方式通知客户。
是否有内置机制或库? 处理这种情况的最佳方法是什么?
答案 0 :(得分:1)
Tornado的RequestHandler可以接受来自客户端的POST,将任务添加到队列中,并回答“好吧我得到了”:
q = collections.deque()
class MyHandler(RequestHandler):
def post(self):
# Your code determines what work the client requests:
task_info = parse(self.request.body)
q.append(task_info)
self.finish(json.dumps({'ok': 1}))
客户端应该生成一个唯一的task_id,并将其包含在POST的信息中。
如果您想要更复杂的任务队列,可以查看my Toro project。或者更简单的方法是使用Tornado PeriodicCallback来检查队列中是否有任务。
那么如何通知客户任务完成?如果客户端是浏览器,我建议使用websocket连接。这是Tornado's websocket documentation。当有人访问您的页面时,某些Javascript应该打开与服务器的websocket连接。当访问者提交任务时,Javascript first 会生成task_id,订阅有关该task_id的通知,然后将任务信息POST到服务器。使用Javascript:
var ws = new WebSocket("ws://localhost:8888/websocket");
ws.onmessage = function (evt) {
alert(evt.data);
};
/* Tell the server we want to know about this task */
function subscribe(task_id) {
ws.send(JSON.stringify({task_id: task_id}));
}
这是服务器的websocket处理程序:
notifiers = set()
class TaskNotifier(websocket.WebSocketHandler):
def open(self):
notifiers.add(self)
def on_message(self, message):
# Client is asking to subscribe to notifications about
# a certain task_id.
parsed = json.loads(message)
self.task_id = parsed['task_id']
def on_close(self):
notifiers.discard(self)
现在,只要你的代码从q
中提取任务并完成它,它就会(在Python中):
for n in notifiers:
if n.task_id == task_id:
n.write_message('task %s done' % task_id)
然后浏览器中的Javascript客户端检测到它正在等待的任务已完成。
请注意,客户端在实际将任务提交给服务器之前会预订有关任务的通知;这确保没有竞争条件,即使服务器很快完成任务。