服务超时时杀死单个线程

时间:2019-10-08 13:03:11

标签: python flask timeout

我正在构建一个python flask服务,为此我尝试为每个单独的POST请求设置超时。 据我了解,只要有人向我的RESTful服务发送发布请求,就会有一个新线程(虚拟或真实)开始执行它。

现在,为了使我的服务器能够处理大量请求,如果进程运行的时间超过为每个POST方法设置的为其定义的恒定时间(TIMEOUT_TIME),我希望它返回超时响应,并停止执行那个单独的线程。

您能给我提出一个可以使用烧瓶方法实现的抽象方案吗?

1 个答案:

答案 0 :(得分:0)

一种方法是在单独的进程中运行请求处理,如果超过超时则终止请求:

onRun

在此示例中,当睡眠java.lang.RuntimeException: java.lang.RuntimeException: java.lang.ClassNotFoundException: Class >com.learning.rackawareness.RackAwareness not found at org.apache.hadoop.conf.Configuration.getClass(Configuration.java:2227) at org.apache.hadoop.hdfs.server.blockmanagement.DatanodeManager.<init>(DatanodeManager.java:208) at org.apache.hadoop.hdfs.server.blockmanagement.BlockManager.<init>(BlockManager.java:268) at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.<init>(FSNamesystem.java:737) at org.apache.hadoop.hdfs.server.namenode.SecondaryNameNode.initialize(SecondaryNameNode.java:246) at org.apache.hadoop.hdfs.server.namenode.SecondaryNameNode.<init>(SecondaryNameNode.java:192) at org.apache.hadoop.hdfs.server.namenode.SecondaryNameNode.main(SecondaryNameNode.java:671) Caused by: java.lang.RuntimeException: java.lang.ClassNotFoundException: Class >com.learning.rackawareness.RackAwareness not found at org.apache.hadoop.conf.Configuration.getClass(Configuration.java:2195) at org.apache.hadoop.conf.Configuration.getClass(Configuration.java:2219) ... 6 more Caused by: java.lang.ClassNotFoundException: Class >com.learning.rackawareness.RackAwareness not found at org.apache.hadoop.conf.Configuration.getClassByName(Configuration.java:2101) at org.apache.hadoop.conf.Configuration.getClass(Configuration.java:2193) ... 7 more 小于给定的#!/usr/bin/env python3 import time from multiprocessing import Process from flask import Flask, request, jsonify app = Flask(__name__) @app.route('/api/sleep', methods=['POST']) def sleep(): duration = int(request.args.get('duration', 1)) timeout = float(request.args.get('timeout', 2)) proc = Process(target=process_request, args=(duration,)) proc.start() proc.join(timeout) if proc.is_alive(): proc.terminate() proc.join() return jsonify(success=False, message='timeout exceeded'), 408 return jsonify(success=True, message='well done') def process_request(t): time.sleep(t) if __name__ == '__main__': app.run(host='localhost', port=8080, debug=True) 时,用户将获得成功的响应:

duration

否则,用户将收到timeout错误:

curl -X POST http://localhost:8080/api/sleep?duration=1\&timeout=2
{
  "message": "well done", 
  "success": true
}

docs

中指出了这种方法的问题
  

请注意,退出处理程序和finally子句等将不会执行。

这意味着运行中的进程将无法在退出前进行清理,这可能会导致问题。另一种解决方案是使用特殊的408线程,该线程将在以后超过超时的情况下用于加入工作进程或线程:

curl -X POST http://localhost:8080/api/sleep?duration=2\&timeout=1
{
  "message": "timeout exceeded", 
  "success": false
}

在这里,在运行烧瓶服务器之前,已创建并启动Joiner线程实例。服务器停止后,我们将#!/usr/bin/env python3 import time from queue import Queue from threading import Thread from flask import Flask, request, jsonify class Joiner(Thread): def __init__(self): super().__init__() self.workers = Queue() def run(self): while True: worker = self.workers.get() if worker is None: break worker.join() app = Flask(__name__) @app.route('/api/sleep', methods=['POST']) def sleep(): duration = int(request.args.get('duration', 1)) timeout = int(request.args.get('timeout', 2)) worker = Thread(target=process_request, args=(duration,)) worker.start() worker.join(timeout) if worker.is_alive(): joiner.workers.put(worker) return jsonify(success=False, message='timeout exceeded'), 408 return jsonify(success=True, message='well done') def process_request(t): time.sleep(t) if __name__ == '__main__': joiner = Joiner() joiner.start() app.run(host='localhost', port=8080, debug=True) joiner.workers.put(None) joiner.join() 放入Joiner队列中,以通知None线程完成。