"server.py"
的服务器,用作GitLab的提交后webhook。"server.py"
内,有一个长时间运行的过程(约40秒)#!/usr/bin/env python
import time
from flask import Flask, abort, jsonify
debug = True
app = Flask(__name__)
@app.route("/", methods=['POST'])
def compile_metadata():
# the long running process...
time.sleep(40)
# end the long running process
return jsonify({"success": True})
if __name__ == "__main__":
app.run(host='0.0.0.0', port=8082, debug=debug, threaded=True)
GitLab的webhooks期望快速返回返回代码。因为我的webhook在40秒左右后返回; GitLab发送重试,在循环中发送长时间运行的进程,直到GitLab尝试了太多次。
我能否将Flask的状态代码返回给GitLab,但仍然运行我的长时间运行过程?
我尝试过添加以下内容:
...
def compile_metadata():
abort(200)
# the long running process
time.sleep(40)
但abort()
仅支持失败代码。
我也尝试过使用@after_this_request
:
@app.route("/", methods=['POST'])
def webhook():
@after_this_request
def compile_metadata(response):
# the long running process...
print("Starting long running process...")
time.sleep(40)
print("Process ended!")
# end the long running process
return jsonify({"success": True})
通常情况下,flask只从python的return
语句返回一个状态代码,但我显然不能在长时间运行的进程之前使用它,因为它将从函数中逃脱。
注意:我实际上并没在我的代码中使用time.sleep(40)
。这只适用于子孙后代和SSCCE。它将返回相同的结果
答案 0 :(得分:0)
让compile_metadata
生成一个线程来处理长时间运行的任务,然后立即返回结果代码(即,不等待线程完成)。确保对可以生成的并发线程数包含一些限制。
对于稍微强大且可扩展的解决方案,请考虑基于消息队列的排序解决方案,如celery。
对于记录,一个简单的解决方案可能如下:
import time
import threading
from flask import Flask, abort, jsonify
debug = True
app = Flask(__name__)
def long_running_task():
print 'start'
time.sleep(40)
print 'finished'
@app.route("/", methods=['POST'])
def compile_metadata():
# the long running process...
t = threading.Thread(target=long_running_task)
t.start()
# end the long running process
return jsonify({"success": True})
if __name__ == "__main__":
app.run(host='0.0.0.0', port=8082, debug=debug, threaded=True)
答案 1 :(得分:0)
当您想快速从服务器返回响应并且仍然做一些耗时的工作时,通常应该使用某种共享存储(例如Redis)来快速存储所需的所有内容,然后返回状态代码。因此,请求可以很快得到处理。
并有一个单独的服务器来例行该语义作业队列来执行耗时的工作。然后,在工作完成后将其从队列中删除。也许也将最终结果存储在共享存储中。这是正常的方法,并且可以很好地扩展。例如,如果您的作业队列增长太快而无法跟上单个服务器的速度,则可以添加更多服务器来处理该共享队列。
但是,即使您不需要可伸缩性,它也是理解,实现和调试的非常简单的设计。如果您的请求负载意外增加,则仅表示您的单独服务器可能整夜都在忙碌。而且您可以放心,如果关闭服务器,则不会丢失任何未完成的工作,因为它们在共享存储中是安全的。
但是,如果您拥有一台服务器来做所有事情,在后台异步执行长时间运行的任务,我想也许只是要确保后台工作是这样发生的:
1. Create a Xib of UIView and design it what ever you want.
2. Create a UIView class
3. Change the fileOwner of Your UIView XIB to the created UIView class
4. Create an Outlet of ContentView in YourView.h
@property (strong, nonatomic) IBOutlet UIView *contentView;
5. Add the following codes in YouView.m
-(instancetype)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if(self)
{
[self customInit];
}
return self;
}
-(instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if(self)
{
[self customInit];
}
return self;
}
-(void) customInit
{
[[NSBundle mainBundle]loadNibNamed:@"View" owner:self options:nil];
[self addSubview:self.contentView];
self.contentView.frame = self.bounds;
}
6. Use this UIView in your ViewController what ever you want.
YourView *YourViewObj = [[YourView alloc] initWithFrame:CGRectMake(0, 0, 100,100)];
[self.view addSubview:YourViewObj];
不是这样的:
------------ Serving Responses
---- Background Work
否则,如果服务器正在后台执行某些工作块,则可能会不响应新请求,具体取决于耗时的工作花费了多长时间(即使请求负载很少)。但是,如果客户超时并重试,我认为您仍然可以避免双重工作。但是,失去未完成的工作并不安全。
答案 2 :(得分:-1)
我可以使用multiprocessing.dummy.Pool
来实现这一目标。在使用threading.Thread
后,它被证明无益,因为Flask仍会等待线程完成(即使使用t.daemon = True
)
我实现了在长时间运行的任务之前返回状态代码的结果,如:
#!/usr/bin/env python
import time
from flask import Flask, jsonify, request
from multiprocessing.dummy import Pool
debug = True
app = Flask(__name__)
pool = Pool(10)
def compile_metadata(data):
print("Starting long running process...")
print(data['user']['email'])
time.sleep(5)
print("Process ended!")
@app.route('/', methods=['POST'])
def webhook():
data = request.json
pool.apply_async(compile_metadata, [data])
return jsonify({"success": True}), 202
if __name__ == "__main__":
app.run(host='0.0.0.0', port=8082, debug=debug, threaded=True)