需求:当接口耗时比较长,超过 20/30s 时,能够在超时之前返回给前端
在这里主要介绍两种方式:
- 信号:配合
signal
模块使用(Windows 不支持) - 多线程
1. signal 信号
import signal
from flask import Flask, jsonify
app = Flask(__name__)
@app.route('/query')
def query():
# 设置超时时间为20秒
timeout = 20
# 设置超时信号处理函数
def handler(signum, frame):
raise TimeoutError('Query timed out after {} seconds'.format(timeout))
# 注册超时信号处理函数
signal.signal(signal.SIGALRM, handler)
# 设置超时时间
signal.alarm(timeout)
# 查询表数据
try:
# 执行查询操作
result = db.query()
# 取消超时信号
signal.alarm(0)
# 返回查询结果
return jsonify({'result': result})
except TimeoutError as e:
# 查询超时,返回超时信息
return jsonify({'error': str(e)})
except Exception as e:
# 查询出错,返回错误信息
return jsonify({'error': str(e)})
在上述代码中,首先使用signal.signal()
方法注册了一个超时信号处理函数handler
。在handler
函数中,抛出TimeoutError
异常表示超时。然后使用signal.alarm()
方法设置了超时时间,这里是20秒。在查询表数据之前,通过signal.alarm(0)
方法取消超时信号。如果查询过程中出现异常,也会返回错误信息。
这样,在接口查询表数据时,如果查询时间超过20秒,就会触发超时信号,从而中断接口执行,并返回超时信息。
2. 多线程
采用 signal
信号机制需中断耗时操作,如果想耗时操作继续在后台执行,可以使用多线程方案。
import threading
from flask import Flask, jsonify
app = Flask(__name__)
@app.route('/query')
def query():
# 设置超时时间为20秒
timeout = 20
# 获取连接对象
conn = current_app.config['HIVE_CONNECTION']
# 创建游标对象
cursor = conn.cursor()
# 创建线程对象
hql = params.get("hql", "")
# 启动线程
query_thread = HiveQueryThread(query_hive, args=(cursor, hql, current_app._get_current_object()))
query_thread.start()
# 等待线程结束,超时时间为 20s
query_thread.join(timeout)
# 若线程任然在运行,就中断线程并返回超时信息
if query_thread.is_alive():
# cursor.cancel_operation() # 中断 hive 查询 thrift.Thrift.TApplicationException: CancelOperation failed: unknown result
# 返回超时信息
return jsonify({'code': 408, 'msg': '执行超过20s,任务进入后台运行!'})
# 获取查询结果
results = query_thread.get_result()
return jsonify({"code": 200, "msg": "success", "data": results})
多线程:
def query_hive(cursor, hql, task_id, current_thread_app):
"""
hive 查询
"""
res = []
try:
print(f"query: {hql}")
cursor.execute(hql)
# 获取查询结果
res = cursor.fetchall()
print(f"res: {res}")
except:
print(traceback.format_exc())
return res
class HiveQueryThread(Thread):
def __init__(self, func, args):
super(HiveQueryThread, self).__init__()
self.func = func
self.args = args
def run(self):
self.results = self.func(*self.args)
def get_result(self):
"""获取结果"""
try:
return self.results
except Exception:
return []